diff options
author | Srimanta Barua <srimanta.barua1@gmail.com> | 2020-06-14 18:32:39 +0530 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-12-30 20:40:30 +0100 |
commit | 3b31f069f05da8e07cc2faeaa8da8d7876f77321 (patch) | |
tree | 3fa59995bbd95c6b86d928746e31d7e077f6d973 | |
parent | ec08e9e78086243cb07ed335c73c7b8c69d8702e (diff) | |
download | serenity-3b31f069f05da8e07cc2faeaa8da8d7876f77321.zip |
LibTTF: Address code-style comments, gracefully handle load failures.
-rw-r--r-- | Libraries/LibTTF/Cmap.cpp | 10 | ||||
-rw-r--r-- | Libraries/LibTTF/Cmap.h | 19 | ||||
-rw-r--r-- | Libraries/LibTTF/Font.cpp | 319 | ||||
-rw-r--r-- | Libraries/LibTTF/Font.h | 54 | ||||
-rw-r--r-- | Libraries/LibTTF/Glyf.cpp | 100 | ||||
-rw-r--r-- | Libraries/LibTTF/Glyf.h | 36 | ||||
-rw-r--r-- | Libraries/LibTTF/Tables.h | 54 |
7 files changed, 340 insertions, 252 deletions
diff --git a/Libraries/LibTTF/Cmap.cpp b/Libraries/LibTTF/Cmap.cpp index bef847599c..889307f167 100644 --- a/Libraries/LibTTF/Cmap.cpp +++ b/Libraries/LibTTF/Cmap.cpp @@ -24,8 +24,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "Cmap.h" #include <AK/Optional.h> +#include <LibTTF/Cmap.h> namespace TTF { @@ -148,4 +148,12 @@ u32 Cmap::glyph_id_for_codepoint(u32 codepoint) const return subtable.glyph_id_for_codepoint(codepoint); } +Optional<Cmap> Cmap::from_slice(const ByteBuffer& slice) +{ + if (slice.size() < (size_t) Sizes::TableHeader) { + return {}; + } + return Cmap(slice); +} + } diff --git a/Libraries/LibTTF/Cmap.h b/Libraries/LibTTF/Cmap.h index 83dd48f88e..4ba4a5c4b4 100644 --- a/Libraries/LibTTF/Cmap.h +++ b/Libraries/LibTTF/Cmap.h @@ -96,17 +96,11 @@ public: u32 glyph_id_for_codepoint_table_12(u32 codepoint) const; ByteBuffer m_slice; - u16 m_raw_platform_id; - u16 m_encoding_id; + u16 m_raw_platform_id { 0 }; + u16 m_encoding_id { 0 }; }; - Cmap() {} - Cmap(const ByteBuffer& slice) - : m_slice(slice) - { - ASSERT(m_slice.size() > (size_t) Sizes::TableHeader); - } - + static Optional<Cmap> from_slice(const ByteBuffer&); u32 num_subtables() const; Optional<Subtable> subtable(u32 index) const; void set_active_index(u32 index) { m_active_index = index; } @@ -124,8 +118,13 @@ private: EncodingRecord = 8, }; + Cmap(const ByteBuffer& slice) + : m_slice(slice) + { + } + ByteBuffer m_slice; u32 m_active_index { UINT32_MAX }; }; -}
\ No newline at end of file +} diff --git a/Libraries/LibTTF/Font.cpp b/Libraries/LibTTF/Font.cpp index dc3157c0de..6a714869e0 100644 --- a/Libraries/LibTTF/Font.cpp +++ b/Libraries/LibTTF/Font.cpp @@ -24,117 +24,152 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "Cmap.h" -#include "Font.h" -#include "Glyf.h" -#include "Tables.h" +#include "AK/ByteBuffer.h" #include <AK/LogStream.h> -#include <AK/Utf8View.h> #include <AK/Utf32View.h> -#include <bits/stdint.h> +#include <AK/Utf8View.h> #include <LibCore/File.h> +#include <LibTTF/Cmap.h> +#include <LibTTF/Font.h> +#include <LibTTF/Glyf.h> +#include <LibTTF/Tables.h> +#include <bits/stdint.h> #include <math.h> namespace TTF { u16 be_u16(const u8* ptr) { - return (((u16) ptr[0]) << 8) | ((u16) ptr[1]); + return (((u16)ptr[0]) << 8) | ((u16)ptr[1]); } u32 be_u32(const u8* ptr) { - return (((u32) ptr[0]) << 24) | (((u32) ptr[1]) << 16) | (((u32) ptr[2]) << 8) | ((u32) ptr[3]); + return (((u32)ptr[0]) << 24) | (((u32)ptr[1]) << 16) | (((u32)ptr[2]) << 8) | ((u32)ptr[3]); } i16 be_i16(const u8* ptr) { - return (((i16) ptr[0]) << 8) | ((i16) ptr[1]); + return (((i16)ptr[0]) << 8) | ((i16)ptr[1]); } float be_fword(const u8* ptr) { - return (float) be_i16(ptr) / (float) (1 << 14); + return (float)be_i16(ptr) / (float)(1 << 14); } -u32 tag_from_str(const char *str) +u32 tag_from_str(const char* str) { - return be_u32((const u8*) str); + return be_u32((const u8*)str); +} + +Optional<Head> Head::from_slice(const ByteBuffer& slice) +{ + if (slice.size() < (size_t)Sizes::Table) { + return {}; + } + return Head(slice); } u16 Head::units_per_em() const { - return be_u16(m_slice.offset_pointer((u32) Offsets::UnitsPerEM)); + return be_u16(m_slice.offset_pointer((u32)Offsets::UnitsPerEM)); } i16 Head::xmin() const { - return be_i16(m_slice.offset_pointer((u32) Offsets::XMin)); + return be_i16(m_slice.offset_pointer((u32)Offsets::XMin)); } i16 Head::ymin() const { - return be_i16(m_slice.offset_pointer((u32) Offsets::YMin)); + return be_i16(m_slice.offset_pointer((u32)Offsets::YMin)); } i16 Head::xmax() const { - return be_i16(m_slice.offset_pointer((u32) Offsets::XMax)); + return be_i16(m_slice.offset_pointer((u32)Offsets::XMax)); } i16 Head::ymax() const { - return be_i16(m_slice.offset_pointer((u32) Offsets::YMax)); + return be_i16(m_slice.offset_pointer((u32)Offsets::YMax)); } u16 Head::lowest_recommended_ppem() const { - return be_u16(m_slice.offset_pointer((u32) Offsets::LowestRecPPEM)); + return be_u16(m_slice.offset_pointer((u32)Offsets::LowestRecPPEM)); } IndexToLocFormat Head::index_to_loc_format() const { - i16 raw = be_i16(m_slice.offset_pointer((u32) Offsets::IndexToLocFormat)); + i16 raw = be_i16(m_slice.offset_pointer((u32)Offsets::IndexToLocFormat)); switch (raw) { - case 0: - return IndexToLocFormat::Offset16; - case 1: - return IndexToLocFormat::Offset32; - default: - ASSERT_NOT_REACHED(); + case 0: return IndexToLocFormat::Offset16; + case 1: return IndexToLocFormat::Offset32; + default: ASSERT_NOT_REACHED(); } } +Optional<Hhea> Hhea::from_slice(const ByteBuffer& slice) +{ + if (slice.size() < (size_t)Sizes::Table) { + return {}; + } + return Hhea(slice); +} + i16 Hhea::ascender() const { - return be_i16(m_slice.offset_pointer((u32) Offsets::Ascender)); + return be_i16(m_slice.offset_pointer((u32)Offsets::Ascender)); } i16 Hhea::descender() const { - return be_i16(m_slice.offset_pointer((u32) Offsets::Descender)); + return be_i16(m_slice.offset_pointer((u32)Offsets::Descender)); } i16 Hhea::line_gap() const { - return be_i16(m_slice.offset_pointer((u32) Offsets::LineGap)); + return be_i16(m_slice.offset_pointer((u32)Offsets::LineGap)); } u16 Hhea::advance_width_max() const { - return be_u16(m_slice.offset_pointer((u32) Offsets::AdvanceWidthMax)); + return be_u16(m_slice.offset_pointer((u32)Offsets::AdvanceWidthMax)); } u16 Hhea::number_of_h_metrics() const { - return be_u16(m_slice.offset_pointer((u32) Offsets::NumberOfHMetrics)); + return be_u16(m_slice.offset_pointer((u32)Offsets::NumberOfHMetrics)); +} + +Optional<Maxp> Maxp::from_slice(const ByteBuffer& slice) +{ + if (slice.size() < (size_t)Sizes::TableV0p5) { + return {}; + } + return Maxp(slice); +} + +u16 Maxp::num_glyphs() const +{ + return be_u16(m_slice.offset_pointer((u32)Offsets::NumGlyphs)); +} + +Optional<Hmtx> Hmtx::from_slice(const ByteBuffer& slice, u32 num_glyphs, u32 number_of_h_metrics) +{ + if (slice.size() < number_of_h_metrics * (u32)Sizes::LongHorMetric + (num_glyphs - number_of_h_metrics) * (u32)Sizes::LeftSideBearing) { + return {}; + } + return Hmtx(slice, num_glyphs, number_of_h_metrics); } GlyphHorizontalMetrics Hmtx::get_glyph_horizontal_metrics(u32 glyph_id) const { ASSERT(glyph_id < m_num_glyphs); if (glyph_id < m_number_of_h_metrics) { - auto offset = glyph_id * (u32) Sizes::LongHorMetric; + auto offset = glyph_id * (u32)Sizes::LongHorMetric; u16 advance_width = be_u16(m_slice.offset_pointer(offset)); i16 left_side_bearing = be_i16(m_slice.offset_pointer(offset + 2)); return GlyphHorizontalMetrics { @@ -142,8 +177,8 @@ GlyphHorizontalMetrics Hmtx::get_glyph_horizontal_metrics(u32 glyph_id) const .left_side_bearing = left_side_bearing, }; } - auto offset = m_number_of_h_metrics * (u32) Sizes::LongHorMetric + (glyph_id - m_number_of_h_metrics) * (u32) Sizes::LeftSideBearing; - u16 advance_width = be_u16(m_slice.offset_pointer((m_number_of_h_metrics - 1) * (u32) Sizes::LongHorMetric)); + auto offset = m_number_of_h_metrics * (u32)Sizes::LongHorMetric + (glyph_id - m_number_of_h_metrics) * (u32)Sizes::LeftSideBearing; + u16 advance_width = be_u16(m_slice.offset_pointer((m_number_of_h_metrics - 1) * (u32)Sizes::LongHorMetric)); i16 left_side_bearing = be_i16(m_slice.offset_pointer(offset)); return GlyphHorizontalMetrics { .advance_width = advance_width, @@ -151,11 +186,6 @@ GlyphHorizontalMetrics Hmtx::get_glyph_horizontal_metrics(u32 glyph_id) const }; } -u16 Maxp::num_glyphs() const -{ - return be_u16(m_slice.offset_pointer((u32) Offsets::NumGlyphs)); -} - RefPtr<Font> Font::load_from_file(const StringView& path, unsigned index) { auto file_or_error = Core::File::open(String(path), Core::IODevice::ReadOnly); @@ -176,12 +206,12 @@ RefPtr<Font> Font::load_from_file(const StringView& path, unsigned index) u32 tag = be_u32(buffer.data()); if (tag == tag_from_str("ttcf")) { // It's a font collection - if (buffer.size() < (u32) Sizes::TTCHeaderV1 + sizeof(u32) * (index + 1)) { + if (buffer.size() < (u32)Sizes::TTCHeaderV1 + sizeof(u32) * (index + 1)) { dbg() << "Font file too small"; return nullptr; } - u32 offset = be_u32(buffer.offset_pointer((u32) Sizes::TTCHeaderV1 + sizeof(u32) * index)); - return adopt(*new Font(move(buffer), offset)); + u32 offset = be_u32(buffer.offset_pointer((u32)Sizes::TTCHeaderV1 + sizeof(u32) * index)); + return load_from_offset(move(buffer), offset); } if (tag == tag_from_str("OTTO")) { dbg() << "CFF fonts not supported yet"; @@ -191,163 +221,190 @@ RefPtr<Font> Font::load_from_file(const StringView& path, unsigned index) dbg() << "Not a valid font"; return nullptr; } - return adopt(*new Font(move(buffer), 0)); + return load_from_offset(move(buffer), 0); } // 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 + (u32) Sizes::OffsetTable); - Optional<ByteBuffer> head_slice = {}; - Optional<ByteBuffer> hhea_slice = {}; - Optional<ByteBuffer> maxp_slice = {}; - Optional<ByteBuffer> hmtx_slice = {}; - Optional<ByteBuffer> cmap_slice = {}; - Optional<ByteBuffer> loca_slice = {}; - Optional<ByteBuffer> glyf_slice = {}; - - //auto sfnt_version = be_u32(data + offset); - auto num_tables = be_u16(m_buffer.offset_pointer(offset + (u32) Offsets::NumTables)); - ASSERT(m_buffer.size() >= offset + (u32) Sizes::OffsetTable + num_tables * (u32) Sizes::TableRecord); +RefPtr<Font> Font::load_from_offset(ByteBuffer&& buffer, u32 offset) +{ + if (buffer.size() < offset + (u32)Sizes::OffsetTable) { + dbg() << "Font file too small"; + return nullptr; + } + + Optional<ByteBuffer> opt_head_slice = {}; + Optional<ByteBuffer> opt_hhea_slice = {}; + Optional<ByteBuffer> opt_maxp_slice = {}; + Optional<ByteBuffer> opt_hmtx_slice = {}; + Optional<ByteBuffer> opt_cmap_slice = {}; + Optional<ByteBuffer> opt_loca_slice = {}; + Optional<ByteBuffer> opt_glyf_slice = {}; + + Optional<Head> opt_head = {}; + Optional<Hhea> opt_hhea = {}; + Optional<Maxp> opt_maxp = {}; + Optional<Hmtx> opt_hmtx = {}; + Optional<Cmap> opt_cmap = {}; + Optional<Loca> opt_loca = {}; + + auto num_tables = be_u16(buffer.offset_pointer(offset + (u32)Offsets::NumTables)); + if (buffer.size() < offset + (u32)Sizes::OffsetTable + num_tables * (u32)Sizes::TableRecord) { + dbg() << "Font file too small"; + return nullptr; + } for (auto i = 0; i < num_tables; i++) { - u32 record_offset = offset + (u32) Sizes::OffsetTable + i * (u32) Sizes::TableRecord; - u32 tag = be_u32(m_buffer.offset_pointer(record_offset)); - u32 table_offset = be_u32(m_buffer.offset_pointer(record_offset + (u32) Offsets::TableRecord_Offset)); - u32 table_length = be_u32(m_buffer.offset_pointer(record_offset + (u32) Offsets::TableRecord_Length)); - ASSERT(m_buffer.size() >= table_offset + table_length); - auto buffer = ByteBuffer::wrap(m_buffer.offset_pointer(table_offset), table_length); + u32 record_offset = offset + (u32)Sizes::OffsetTable + i * (u32)Sizes::TableRecord; + u32 tag = be_u32(buffer.offset_pointer(record_offset)); + u32 table_offset = be_u32(buffer.offset_pointer(record_offset + (u32)Offsets::TableRecord_Offset)); + u32 table_length = be_u32(buffer.offset_pointer(record_offset + (u32)Offsets::TableRecord_Length)); + if (buffer.size() < table_offset + table_length) { + dbg() << "Font file too small"; + return nullptr; + } + auto buffer_here = ByteBuffer::wrap(buffer.offset_pointer(table_offset), table_length); // Get the table offsets we need. if (tag == tag_from_str("head")) { - head_slice = buffer; + opt_head_slice = buffer_here; } else if (tag == tag_from_str("hhea")) { - hhea_slice = buffer; + opt_hhea_slice = buffer_here; } else if (tag == tag_from_str("maxp")) { - maxp_slice = buffer; + opt_maxp_slice = buffer_here; } else if (tag == tag_from_str("hmtx")) { - hmtx_slice = buffer; + opt_hmtx_slice = buffer_here; } else if (tag == tag_from_str("cmap")) { - cmap_slice = buffer; + opt_cmap_slice = buffer_here; } else if (tag == tag_from_str("loca")) { - loca_slice = buffer; + opt_loca_slice = buffer_here; } else if (tag == tag_from_str("glyf")) { - glyf_slice = buffer; + opt_glyf_slice = buffer_here; } } - // 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_slice = head_slice.value(); - m_hhea_slice = hhea_slice.value(); - m_maxp_slice = maxp_slice.value(); - m_hmtx_slice = hmtx_slice.value(); - m_loca_slice = loca_slice.value(); - m_glyf_slice = glyf_slice.value(); - - m_cmap = Cmap(cmap_slice.value()); + if (!opt_head_slice.has_value() || !(opt_head = Head::from_slice(opt_head_slice.value())).has_value()) { + dbg() << "Could not load Head"; + return nullptr; + } + auto head = opt_head.value(); + + if (!opt_hhea_slice.has_value() || !(opt_hhea = Hhea::from_slice(opt_hhea_slice.value())).has_value()) { + dbg() << "Could not load Hhea"; + return nullptr; + } + auto hhea = opt_hhea.value(); + + if (!opt_maxp_slice.has_value() || !(opt_maxp = Maxp::from_slice(opt_maxp_slice.value())).has_value()) { + dbg() << "Could not load Maxp"; + return nullptr; + } + auto maxp = opt_maxp.value(); + + if (!opt_hmtx_slice.has_value() || !(opt_hmtx = Hmtx::from_slice(opt_hmtx_slice.value(), maxp.num_glyphs(), hhea.number_of_h_metrics())).has_value()) { + dbg() << "Could not load Hmtx"; + return nullptr; + } + auto hmtx = opt_hmtx.value(); + + if (!opt_cmap_slice.has_value() || !(opt_cmap = Cmap::from_slice(opt_cmap_slice.value())).has_value()) { + dbg() << "Could not load Cmap"; + return nullptr; + } + auto cmap = opt_cmap.value(); + + if (!opt_loca_slice.has_value() || !(opt_loca = Loca::from_slice(opt_loca_slice.value(), maxp.num_glyphs(), head.index_to_loc_format())).has_value()) { + dbg() << "Could not load Loca"; + return nullptr; + } + auto loca = opt_loca.value(); + + if (!opt_glyf_slice.has_value()) { + dbg() << "Could not load Glyf"; + return nullptr; + } + auto glyf = Glyf(opt_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); + for (u32 i = 0; i < cmap.num_subtables(); i++) { + auto opt_subtable = 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() == (u16) Cmap::Subtable::WindowsEncoding::UnicodeFullRepertoire) { - m_cmap.set_active_index(i); + if (subtable.encoding_id() == (u16)Cmap::Subtable::WindowsEncoding::UnicodeFullRepertoire) { + cmap.set_active_index(i); break; } - if (subtable.encoding_id() == (u16) Cmap::Subtable::WindowsEncoding::UnicodeBMP) { - m_cmap.set_active_index(i); + if (subtable.encoding_id() == (u16)Cmap::Subtable::WindowsEncoding::UnicodeBMP) { + cmap.set_active_index(i); break; } } } + + return adopt(*new Font(move(buffer), move(head), move(hhea), move(maxp), move(hmtx), move(cmap), move(loca), move(glyf))); } ScaledFontMetrics Font::metrics(float x_scale, float y_scale) const { - Hhea hhea(m_hhea_slice); - auto ascender = hhea.ascender() * y_scale; - auto descender = hhea.descender() * y_scale; - auto line_gap = hhea.line_gap() * y_scale; - auto advance_width_max = hhea.advance_width_max() * x_scale; + auto ascender = m_hhea.ascender() * y_scale; + auto descender = m_hhea.descender() * y_scale; + auto line_gap = m_hhea.line_gap() * y_scale; + auto advance_width_max = m_hhea.advance_width_max() * x_scale; return ScaledFontMetrics { - .ascender = (int) roundf(ascender), - .descender = (int) roundf(descender), - .line_gap = (int) roundf(line_gap), - .advance_width_max = (int) roundf(advance_width_max), + .ascender = (int)roundf(ascender), + .descender = (int)roundf(descender), + .line_gap = (int)roundf(line_gap), + .advance_width_max = (int)roundf(advance_width_max), }; } // FIXME: "loca" and "glyf" are not available for CFF fonts. ScaledGlyphMetrics Font::glyph_metrics(u32 glyph_id, float x_scale, float y_scale) const { - u32 num_glyphs = glyph_count(); - u16 number_of_h_metrics = Hhea(m_hhea_slice).number_of_h_metrics(); - auto index_to_loc_format = Head(m_head_slice).index_to_loc_format(); - Hmtx hmtx(m_hmtx_slice, num_glyphs, number_of_h_metrics); - Loca loca(m_loca_slice, num_glyphs, index_to_loc_format); - Glyf glyf(m_glyf_slice); - - if (glyph_id >= num_glyphs) { + if (glyph_id >= glyph_count()) { glyph_id = 0; } - auto horizontal_metrics = hmtx.get_glyph_horizontal_metrics(glyph_id); - auto glyph_offset = loca.get_glyph_offset(glyph_id); - auto glyph = glyf.glyph(glyph_offset); + auto horizontal_metrics = m_hmtx.get_glyph_horizontal_metrics(glyph_id); + auto glyph_offset = m_loca.get_glyph_offset(glyph_id); + auto glyph = m_glyf.glyph(glyph_offset); int ascender = glyph.ascender(); int descender = glyph.descender(); return ScaledGlyphMetrics { - .ascender = (int) roundf(ascender * y_scale), - .descender = (int) roundf(descender * y_scale), - .advance_width = (int) roundf(horizontal_metrics.advance_width * x_scale), - .left_side_bearing = (int) roundf(horizontal_metrics.left_side_bearing * x_scale), + .ascender = (int)roundf(ascender * y_scale), + .descender = (int)roundf(descender * y_scale), + .advance_width = (int)roundf(horizontal_metrics.advance_width * x_scale), + .left_side_bearing = (int)roundf(horizontal_metrics.left_side_bearing * x_scale), }; } // FIXME: "loca" and "glyf" are not available for CFF fonts. RefPtr<Gfx::Bitmap> Font::raster_glyph(u32 glyph_id, float x_scale, float y_scale) const { - u32 num_glyphs = glyph_count(); - auto index_to_loc_format = Head(m_head_slice).index_to_loc_format(); - Loca loca(m_loca_slice, num_glyphs, index_to_loc_format); - Glyf glyf(m_glyf_slice); - - if (glyph_id >= num_glyphs) { + if (glyph_id >= glyph_count()) { glyph_id = 0; } - auto glyph_offset = loca.get_glyph_offset(glyph_id); - auto glyph = glyf.glyph(glyph_offset); + auto glyph_offset = m_loca.get_glyph_offset(glyph_id); + auto glyph = m_glyf.glyph(glyph_offset); return glyph.raster(x_scale, y_scale, [&](u16 glyph_id) { - if (glyph_id >= num_glyphs) { + if (glyph_id >= glyph_count()) { glyph_id = 0; } - auto glyph_offset = loca.get_glyph_offset(glyph_id); - return glyf.glyph(glyph_offset); + auto glyph_offset = m_loca.get_glyph_offset(glyph_id); + return m_glyf.glyph(glyph_offset); }); } u32 Font::glyph_count() const { - return Maxp(m_maxp_slice).num_glyphs(); + return m_maxp.num_glyphs(); } u16 Font::units_per_em() const { - return Head(m_head_slice).units_per_em(); + return m_head.units_per_em(); } int ScaledFont::width(const StringView& string) const diff --git a/Libraries/LibTTF/Font.h b/Libraries/LibTTF/Font.h index cf34c43ea8..f430fdcc0d 100644 --- a/Libraries/LibTTF/Font.h +++ b/Libraries/LibTTF/Font.h @@ -26,13 +26,15 @@ #pragma once -#include "Cmap.h" #include <AK/ByteBuffer.h> #include <AK/Noncopyable.h> #include <AK/RefCounted.h> #include <AK/StringView.h> #include <LibGfx/Bitmap.h> #include <LibGfx/Size.h> +#include <LibTTF/Cmap.h> +#include <LibTTF/Glyf.h> +#include <LibTTF/Tables.h> #define POINTS_PER_INCH 72.0f #define DEFAULT_DPI 96 @@ -66,6 +68,13 @@ class Font : public RefCounted<Font> { public: static RefPtr<Font> load_from_file(const StringView& path, unsigned index = 0); + ScaledFontMetrics metrics(float x_scale, float y_scale) const; + ScaledGlyphMetrics glyph_metrics(u32 glyph_id, float x_scale, float y_scale) const; + RefPtr<Gfx::Bitmap> raster_glyph(u32 glyph_id, float x_scale, float y_scale) const; + u32 glyph_count() const; + u16 units_per_em() const; + u32 glyph_id_for_codepoint(u32 codepoint) const { return m_cmap.glyph_id_for_codepoint(codepoint); } + private: enum class Offsets { NumTables = 4, @@ -78,26 +87,29 @@ private: TableRecord = 16, }; - Font(ByteBuffer&& buffer, u32 offset); - ScaledFontMetrics metrics(float x_scale, float y_scale) const; - ScaledGlyphMetrics glyph_metrics(u32 glyph_id, float x_scale, float y_scale) const; - RefPtr<Gfx::Bitmap> raster_glyph(u32 glyph_id, float x_scale, float y_scale) const; - u32 glyph_count() const; - u16 units_per_em() const; + static RefPtr<Font> load_from_offset(ByteBuffer&&, unsigned index = 0); + Font(ByteBuffer&& buffer, Head&& head, Hhea&& hhea, Maxp&& maxp, Hmtx&& hmtx, Cmap&& cmap, Loca&& loca, Glyf&& glyf) + : m_buffer(move(buffer)) + , m_head(move(head)) + , m_hhea(move(hhea)) + , m_maxp(move(maxp)) + , m_hmtx(move(hmtx)) + , m_loca(move(loca)) + , m_glyf(move(glyf)) + , m_cmap(move(cmap)) + { + } // This owns the font data ByteBuffer m_buffer; - // These are all non-owning slices - ByteBuffer m_head_slice; - ByteBuffer m_hhea_slice; - ByteBuffer m_maxp_slice; - ByteBuffer m_hmtx_slice; - ByteBuffer m_loca_slice; - ByteBuffer m_glyf_slice; - // These are stateful wrappers around tables + // These are stateful wrappers around non-owning slices + Head m_head; + Hhea m_hhea; + Maxp m_maxp; + Hmtx m_hmtx; + Loca m_loca; + Glyf m_glyf; Cmap m_cmap; - - friend ScaledFont; }; class ScaledFont { @@ -109,7 +121,7 @@ public: m_x_scale = (point_width * dpi_x) / (POINTS_PER_INCH * units_per_em); m_y_scale = (point_height * dpi_y) / (POINTS_PER_INCH * units_per_em); } - u32 glyph_id_for_codepoint(u32 codepoint) const { return m_font->m_cmap.glyph_id_for_codepoint(codepoint); } + u32 glyph_id_for_codepoint(u32 codepoint) const { return m_font->glyph_id_for_codepoint(codepoint); } ScaledFontMetrics metrics() const { return m_font->metrics(m_x_scale, m_y_scale); } ScaledGlyphMetrics glyph_metrics(u32 glyph_id) const { return m_font->glyph_metrics(glyph_id, m_x_scale, m_y_scale); } RefPtr<Gfx::Bitmap> raster_glyph(u32 glyph_id) const { return m_font->raster_glyph(glyph_id, m_x_scale, m_y_scale); } @@ -120,10 +132,8 @@ public: private: RefPtr<Font> m_font; - float m_x_scale; - float m_y_scale; - - friend Font; + float m_x_scale { 0.0 }; + float m_y_scale { 0.0 }; }; } diff --git a/Libraries/LibTTF/Glyf.cpp b/Libraries/LibTTF/Glyf.cpp index f04d62422f..71837a71e4 100644 --- a/Libraries/LibTTF/Glyf.cpp +++ b/Libraries/LibTTF/Glyf.cpp @@ -24,9 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "Glyf.h" #include <LibGfx/FloatPoint.h> #include <LibGfx/Path.h> +#include <LibTTF/Glyf.h> namespace TTF { @@ -95,33 +95,33 @@ public: m_flags_remaining--; } else { m_flag = m_slice[m_flags_offset++]; - if (m_flag & (u8) SimpleGlyfFlags::RepeatFlag) { + if (m_flag & (u8)SimpleGlyfFlags::RepeatFlag) { m_flags_remaining = m_slice[m_flags_offset++]; } } - switch (m_flag & (u8) SimpleGlyfFlags::XMask) { - case (u8) SimpleGlyfFlags::XLongVector: + switch (m_flag & (u8)SimpleGlyfFlags::XMask) { + case (u8)SimpleGlyfFlags::XLongVector: m_last_point.set_x(m_last_point.x() + be_i16(m_slice.offset_pointer(m_x_offset))); m_x_offset += 2; break; - case (u8) SimpleGlyfFlags::XNegativeShortVector: + case (u8)SimpleGlyfFlags::XNegativeShortVector: m_last_point.set_x(m_last_point.x() - m_slice[m_x_offset++]); break; - case (u8) SimpleGlyfFlags::XPositiveShortVector: + case (u8)SimpleGlyfFlags::XPositiveShortVector: m_last_point.set_x(m_last_point.x() + m_slice[m_x_offset++]); break; default: break; } - switch (m_flag & (u8) SimpleGlyfFlags::YMask) { - case (u8) SimpleGlyfFlags::YLongVector: + switch (m_flag & (u8)SimpleGlyfFlags::YMask) { + case (u8)SimpleGlyfFlags::YLongVector: m_last_point.set_y(m_last_point.y() + be_i16(m_slice.offset_pointer(m_y_offset))); m_y_offset += 2; break; - case (u8) SimpleGlyfFlags::YNegativeShortVector: + case (u8)SimpleGlyfFlags::YNegativeShortVector: m_last_point.set_y(m_last_point.y() - m_slice[m_y_offset++]); break; - case (u8) SimpleGlyfFlags::YPositiveShortVector: + case (u8)SimpleGlyfFlags::YPositiveShortVector: m_last_point.set_y(m_last_point.y() + m_slice[m_y_offset++]); break; default: @@ -129,7 +129,7 @@ public: } m_points_remaining--; Item ret = { - .on_curve = (m_flag & (u8) SimpleGlyfFlags::OnCurve) != 0, + .on_curve = (m_flag & (u8)SimpleGlyfFlags::OnCurve) != 0, .point = m_affine.map(m_last_point), }; return ret; @@ -147,7 +147,8 @@ private: Gfx::AffineTransform m_affine; }; -Optional<Glyf::Glyph::ComponentIterator::Item> Glyf::Glyph::ComponentIterator::next() { +Optional<Glyf::Glyph::ComponentIterator::Item> Glyf::Glyph::ComponentIterator::next() +{ if (!m_has_more) { return {}; } @@ -156,17 +157,17 @@ Optional<Glyf::Glyph::ComponentIterator::Item> Glyf::Glyph::ComponentIterator::n u16 glyph_id = be_u16(m_slice.offset_pointer(m_offset)); m_offset += 2; i16 arg1 = 0, arg2 = 0; - if (flags & (u16) CompositeGlyfFlags::Arg1AndArg2AreWords) { + if (flags & (u16)CompositeGlyfFlags::Arg1AndArg2AreWords) { arg1 = be_i16(m_slice.offset_pointer(m_offset)); m_offset += 2; arg2 = be_i16(m_slice.offset_pointer(m_offset)); m_offset += 2; } else { - arg1 = (i8) m_slice[m_offset++]; - arg2 = (i8) m_slice[m_offset++]; + arg1 = (i8)m_slice[m_offset++]; + arg2 = (i8)m_slice[m_offset++]; } float a = 1.0, b = 0.0, c = 0.0, d = 1.0, e = 0.0, f = 0.0; - if (flags & (u16) CompositeGlyfFlags::WeHaveATwoByTwo) { + if (flags & (u16)CompositeGlyfFlags::WeHaveATwoByTwo) { a = be_fword(m_slice.offset_pointer(m_offset)); m_offset += 2; b = be_fword(m_slice.offset_pointer(m_offset)); @@ -175,33 +176,33 @@ Optional<Glyf::Glyph::ComponentIterator::Item> Glyf::Glyph::ComponentIterator::n m_offset += 2; d = be_fword(m_slice.offset_pointer(m_offset)); m_offset += 2; - } else if (flags & (u16) CompositeGlyfFlags::WeHaveAnXAndYScale) { + } else if (flags & (u16)CompositeGlyfFlags::WeHaveAnXAndYScale) { a = be_fword(m_slice.offset_pointer(m_offset)); m_offset += 2; d = be_fword(m_slice.offset_pointer(m_offset)); m_offset += 2; - } else if (flags & (u16) CompositeGlyfFlags::WeHaveAScale) { + } else if (flags & (u16)CompositeGlyfFlags::WeHaveAScale) { a = be_fword(m_slice.offset_pointer(m_offset)); m_offset += 2; d = a; } // FIXME: Handle UseMyMetrics, ScaledComponentOffset, UnscaledComponentOffset, non-ArgsAreXYValues - if (flags & (u16) CompositeGlyfFlags::ArgsAreXYValues) { + if (flags & (u16)CompositeGlyfFlags::ArgsAreXYValues) { e = arg1; f = arg2; } else { TODO(); } - if (flags & (u16) CompositeGlyfFlags::UseMyMetrics) { + if (flags & (u16)CompositeGlyfFlags::UseMyMetrics) { TODO(); } - if (flags & (u16) CompositeGlyfFlags::ScaledComponentOffset) { + if (flags & (u16)CompositeGlyfFlags::ScaledComponentOffset) { TODO(); } - if (flags & (u16) CompositeGlyfFlags::UnscaledComponentOffset) { + if (flags & (u16)CompositeGlyfFlags::UnscaledComponentOffset) { TODO(); } - m_has_more = (flags & (u16) CompositeGlyfFlags::MoreComponents); + m_has_more = (flags & (u16)CompositeGlyfFlags::MoreComponents); return Item { .glyph_id = glyph_id, .affine = Gfx::AffineTransform(a, b, c, d, e, f), @@ -278,7 +279,7 @@ void Rasterizer::draw_line(Gfx::FloatPoint p0, Gfx::FloatPoint p1) for (u32 y = y0; y < y1; y++) { u32 line_offset = m_size.width() * y; - float dy = min(y + 1.0f, p1.y()) - max((float) y, p0.y()); + float dy = min(y + 1.0f, p1.y()) - max((float)y, p0.y()); float directed_dy = dy * direction; float x_next = x_cur + dy * dxdy; if (x_next < 0.0) { @@ -318,12 +319,29 @@ void Rasterizer::draw_line(Gfx::FloatPoint p0, Gfx::FloatPoint p1) } } +Optional<Loca> Loca::from_slice(const ByteBuffer& slice, u32 num_glyphs, IndexToLocFormat index_to_loc_format) +{ + switch (index_to_loc_format) { + case IndexToLocFormat::Offset16: + if (slice.size() < num_glyphs * 2) { + return {}; + } + break; + case IndexToLocFormat::Offset32: + if (slice.size() < num_glyphs * 4) { + return {}; + } + break; + } + return Loca(slice, num_glyphs, index_to_loc_format); +} + u32 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; + 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: @@ -331,26 +349,26 @@ u32 Loca::get_glyph_offset(u32 glyph_id) const } } -static void get_ttglyph_offsets(const ByteBuffer& slice, u32 num_points, u32 flags_offset, u32 *x_offset, u32 *y_offset) +static void get_ttglyph_offsets(const ByteBuffer& slice, u32 num_points, u32 flags_offset, u32* x_offset, u32* y_offset) { u32 flags_size = 0; u32 x_size = 0; u32 repeat_count; while (num_points > 0) { u8 flag = slice[flags_offset + flags_size]; - if (flag & (u8) SimpleGlyfFlags::RepeatFlag) { + if (flag & (u8)SimpleGlyfFlags::RepeatFlag) { flags_size++; repeat_count = slice[flags_offset + flags_size] + 1; } else { repeat_count = 1; } flags_size++; - switch (flag & (u8) SimpleGlyfFlags::XMask) { - case (u8) SimpleGlyfFlags::XLongVector: + switch (flag & (u8)SimpleGlyfFlags::XMask) { + case (u8)SimpleGlyfFlags::XLongVector: x_size += repeat_count * 2; break; - case (u8) SimpleGlyfFlags::XNegativeShortVector: - case (u8) SimpleGlyfFlags::XPositiveShortVector: + case (u8)SimpleGlyfFlags::XNegativeShortVector: + case (u8)SimpleGlyfFlags::XPositiveShortVector: x_size += repeat_count; break; default: @@ -392,9 +410,7 @@ void Glyf::Glyph::raster_inner(Rasterizer& rasterizer, Gfx::AffineTransform& aff contour_size = current_contour_end - last_contour_end; last_contour_end = current_contour_end; auto opt_item = point_iterator.next(); - if (!opt_item.has_value()) { - ASSERT_NOT_REACHED(); - } + ASSERT(opt_item.has_value()); contour_start = opt_item.value().point; path.move_to(contour_start.value()); contour_size--; @@ -462,8 +478,8 @@ void Glyf::Glyph::raster_inner(Rasterizer& rasterizer, Gfx::AffineTransform& aff RefPtr<Gfx::Bitmap> Glyf::Glyph::raster_simple(float x_scale, float y_scale) const { - u32 width = (u32) (ceil((m_xmax - m_xmin) * x_scale)) + 2; - u32 height = (u32) (ceil((m_ymax - m_ymin) * y_scale)) + 2; + u32 width = (u32)(ceil((m_xmax - m_xmin) * x_scale)) + 2; + u32 height = (u32)(ceil((m_ymax - m_ymin) * y_scale)) + 2; Rasterizer rasterizer(Gfx::IntSize(width, height)); auto affine = Gfx::AffineTransform().scale(x_scale, -y_scale).translate(-m_xmin, -m_ymax); raster_inner(rasterizer, affine); @@ -472,13 +488,13 @@ RefPtr<Gfx::Bitmap> Glyf::Glyph::raster_simple(float x_scale, float y_scale) con Glyf::Glyph Glyf::glyph(u32 offset) const { - ASSERT(m_slice.size() >= offset + (u32) Sizes::GlyphHeader); + ASSERT(m_slice.size() >= offset + (u32)Sizes::GlyphHeader); i16 num_contours = be_i16(m_slice.offset_pointer(offset)); - i16 xmin = be_i16(m_slice.offset_pointer(offset + (u32) Offsets::XMin)); - i16 ymin = be_i16(m_slice.offset_pointer(offset + (u32) Offsets::YMin)); - i16 xmax = be_i16(m_slice.offset_pointer(offset + (u32) Offsets::XMax)); - i16 ymax = be_i16(m_slice.offset_pointer(offset + (u32) Offsets::YMax)); - auto slice = ByteBuffer::wrap(m_slice.offset_pointer(offset + (u32) Sizes::GlyphHeader), m_slice.size() - offset - (u32) Sizes::GlyphHeader); + i16 xmin = be_i16(m_slice.offset_pointer(offset + (u32)Offsets::XMin)); + i16 ymin = be_i16(m_slice.offset_pointer(offset + (u32)Offsets::YMin)); + i16 xmax = be_i16(m_slice.offset_pointer(offset + (u32)Offsets::XMax)); + i16 ymax = be_i16(m_slice.offset_pointer(offset + (u32)Offsets::YMax)); + auto slice = ByteBuffer::wrap(m_slice.offset_pointer(offset + (u32)Sizes::GlyphHeader), m_slice.size() - offset - (u32)Sizes::GlyphHeader); return Glyph(slice, xmin, ymin, xmax, ymax, num_contours); } diff --git a/Libraries/LibTTF/Glyf.h b/Libraries/LibTTF/Glyf.h index db1d6cb699..59a98a4552 100644 --- a/Libraries/LibTTF/Glyf.h +++ b/Libraries/LibTTF/Glyf.h @@ -26,11 +26,11 @@ #pragma once -#include "Tables.h" #include <AK/ByteBuffer.h> #include <AK/FixedArray.h> #include <LibGfx/AffineTransform.h> #include <LibGfx/Bitmap.h> +#include <LibTTF/Tables.h> #include <math.h> namespace TTF { @@ -50,25 +50,19 @@ private: class Loca { public: + static Optional<Loca> from_slice(const ByteBuffer&, u32 num_glyphs, IndexToLocFormat); + u32 get_glyph_offset(u32 glyph_id) const; + +private: Loca(const ByteBuffer& slice, u32 num_glyphs, IndexToLocFormat index_to_loc_format) : m_slice(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; + u32 m_num_glyphs { 0 }; IndexToLocFormat m_index_to_loc_format; }; @@ -88,7 +82,7 @@ public: m_type = Type::Simple; } } - template <typename GlyphCb> + template<typename GlyphCb> RefPtr<Gfx::Bitmap> raster(float x_scale, float y_scale, GlyphCb glyph_callback) const { switch (m_type) { @@ -129,11 +123,11 @@ public: void raster_inner(Rasterizer&, Gfx::AffineTransform&) const; RefPtr<Gfx::Bitmap> raster_simple(float x_scale, float y_scale) const; - template <typename GlyphCb> + template<typename GlyphCb> RefPtr<Gfx::Bitmap> raster_composite(float x_scale, float y_scale, GlyphCb glyph_callback) const { - u32 width = (u32) (ceil((m_xmax - m_xmin) * x_scale)) + 1; - u32 height = (u32) (ceil((m_ymax - m_ymin) * y_scale)) + 1; + u32 width = (u32)(ceil((m_xmax - m_xmin) * x_scale)) + 1; + u32 height = (u32)(ceil((m_ymax - m_ymin) * y_scale)) + 1; Rasterizer rasterizer(Gfx::IntSize(width, height)); auto affine = Gfx::AffineTransform().scale(x_scale, -y_scale).translate(-m_xmin, -m_ymax); ComponentIterator component_iterator(m_slice); @@ -151,10 +145,10 @@ public: } Type m_type { Type::Composite }; - i16 m_xmin; - i16 m_ymin; - i16 m_xmax; - i16 m_ymax; + i16 m_xmin { 0 }; + i16 m_ymin { 0 }; + i16 m_xmax { 0 }; + i16 m_ymax { 0 }; i16 m_num_contours { -1 }; ByteBuffer m_slice; }; @@ -179,4 +173,4 @@ private: ByteBuffer m_slice; }; -}
\ No newline at end of file +} diff --git a/Libraries/LibTTF/Tables.h b/Libraries/LibTTF/Tables.h index 583f5358b4..b792136bd2 100644 --- a/Libraries/LibTTF/Tables.h +++ b/Libraries/LibTTF/Tables.h @@ -37,11 +37,7 @@ enum class IndexToLocFormat { class Head { public: - Head(const ByteBuffer& slice) - : m_slice(slice) - { - ASSERT(m_slice.size() >= (size_t) Sizes::Table); - } + static Optional<Head> from_slice(const ByteBuffer&); u16 units_per_em() const; i16 xmin() const; i16 ymin() const; @@ -64,16 +60,17 @@ private: Table = 54, }; + Head(const ByteBuffer& slice) + : m_slice(slice) + { + } + ByteBuffer m_slice; }; class Hhea { public: - Hhea(const ByteBuffer& slice) - : m_slice(slice) - { - ASSERT(m_slice.size() >= (size_t) Sizes::Table); - } + static Optional<Hhea> from_slice(const ByteBuffer&); i16 ascender() const; i16 descender() const; i16 line_gap() const; @@ -92,16 +89,17 @@ private: Table = 36, }; + Hhea(const ByteBuffer& slice) + : m_slice(slice) + { + } + ByteBuffer m_slice; }; class Maxp { public: - Maxp(const ByteBuffer& slice) - : m_slice(slice) - { - ASSERT(m_slice.size() >= (size_t) Sizes::TableV0p5); - } + static Optional<Maxp> from_slice(const ByteBuffer&); u16 num_glyphs() const; private: @@ -112,6 +110,11 @@ private: TableV0p5 = 6, }; + Maxp(const ByteBuffer& slice) + : m_slice(slice) + { + } + ByteBuffer m_slice; }; @@ -122,13 +125,7 @@ struct GlyphHorizontalMetrics { class Hmtx { public: - Hmtx(const ByteBuffer& slice, u32 num_glyphs, u32 number_of_h_metrics) - : m_slice(slice) - , m_num_glyphs(num_glyphs) - , m_number_of_h_metrics(number_of_h_metrics) - { - ASSERT(m_slice.size() >= number_of_h_metrics * (u32) Sizes::LongHorMetric + (num_glyphs - number_of_h_metrics) * (u32) Sizes::LeftSideBearing); - } + static Optional<Hmtx> from_slice(const ByteBuffer&, u32 num_glyphs, u32 number_of_h_metrics); GlyphHorizontalMetrics get_glyph_horizontal_metrics(u32 glyph_id) const; private: @@ -137,9 +134,16 @@ private: LeftSideBearing = 2 }; + Hmtx(const ByteBuffer& slice, u32 num_glyphs, u32 number_of_h_metrics) + : m_slice(slice) + , m_num_glyphs(num_glyphs) + , m_number_of_h_metrics(number_of_h_metrics) + { + } + ByteBuffer m_slice; - u32 m_num_glyphs; - u32 m_number_of_h_metrics; + u32 m_num_glyphs { 0 }; + u32 m_number_of_h_metrics { 0 }; }; -}
\ No newline at end of file +} |