From 5efe80af7f8521dc15c4d4445f899e305f974fcb Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 20 Feb 2024 11:31:33 -0500 Subject: [PATCH] LibPDF+LibGfx: Do not try to read "name" table for PDFs It is often missing in fonts embedded in PDFs. 75 of my 1000 test files complained "Font is missing Name" when trying to read fonts before. Increases number of PDFs that render without diagnostics from 682 to 743. --- .../Libraries/LibGfx/Font/OpenType/Font.cpp | 23 +++++++++++++------ .../Libraries/LibGfx/Font/OpenType/Font.h | 10 ++++++-- Userland/Libraries/LibPDF/Fonts/PDFFont.h | 5 ++++ .../Libraries/LibPDF/Fonts/TrueTypeFont.cpp | 2 +- Userland/Libraries/LibPDF/Fonts/Type0Font.cpp | 2 +- 5 files changed, 31 insertions(+), 11 deletions(-) diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp b/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp index a7eaedc608..23d89cb498 100644 --- a/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp +++ b/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp @@ -256,9 +256,12 @@ ErrorOr> Font::try_load_from_offset(ReadonlyBytes buffer, u3 return Error::from_string_literal("Font is missing Head"); auto head = TRY(Head::from_slice(opt_head_slice.value())); - if (!opt_name_slice.has_value()) - return Error::from_string_literal("Font is missing Name"); - auto name = TRY(Name::from_slice(opt_name_slice.value())); + Optional name; + if (!(options.skip_tables & Options::SkipTables::Name)) { + if (!opt_name_slice.has_value()) + return Error::from_string_literal("Font is missing Name"); + name = TRY(Name::from_slice(opt_name_slice.value())); + } if (!opt_hhea_slice.has_value()) return Error::from_string_literal("Font is missing Hhea"); @@ -544,12 +547,15 @@ u16 Font::units_per_em() const String Font::family() const { + if (!m_name.has_value()) + return {}; + if (!m_family.has_value()) { m_family = [&] { - auto string = m_name.typographic_family_name(); + auto string = m_name->typographic_family_name(); if (!string.is_empty()) return string; - return m_name.family_name(); + return m_name->family_name(); }(); } return *m_family; @@ -557,10 +563,13 @@ String Font::family() const String Font::variant() const { - auto string = m_name.typographic_subfamily_name(); + if (!m_name.has_value()) + return {}; + + auto string = m_name->typographic_subfamily_name(); if (!string.is_empty()) return string; - return m_name.subfamily_name(); + return m_name->subfamily_name(); } u16 Font::weight() const diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Font.h b/Userland/Libraries/LibGfx/Font/OpenType/Font.h index 722ba26bff..16b5c61ba5 100644 --- a/Userland/Libraries/LibGfx/Font/OpenType/Font.h +++ b/Userland/Libraries/LibGfx/Font/OpenType/Font.h @@ -30,6 +30,12 @@ public: struct FontOptions { unsigned index { 0 }; OwnPtr external_cmap {}; + + enum SkipTables { + // If set, do not try to read the 'name' table. family() and variant() will return empty strings. + Name = 1 << 0, + }; + u32 skip_tables { 0 }; }; class Font : public Gfx::VectorFont { @@ -85,7 +91,7 @@ private: Font( Head&& head, - Name&& name, + Optional&& name, Hhea&& hhea, Maxp&& maxp, Hmtx&& hmtx, @@ -121,7 +127,7 @@ private: // These are stateful wrappers around non-owning slices Head m_head; - Name m_name; + Optional m_name; Hhea m_hhea; Maxp m_maxp; Hmtx m_hmtx; diff --git a/Userland/Libraries/LibPDF/Fonts/PDFFont.h b/Userland/Libraries/LibPDF/Fonts/PDFFont.h index 722bf13900..cc3b33bac0 100644 --- a/Userland/Libraries/LibPDF/Fonts/PDFFont.h +++ b/Userland/Libraries/LibPDF/Fonts/PDFFont.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -16,6 +17,10 @@ namespace PDF { class Renderer; +// PDF files don't need most of the data in OpenType fonts, and even contain invalid data for +// these tables in some cases. Skip reading these tables. +constexpr u32 pdf_skipped_opentype_tables = OpenType::FontOptions::SkipTables::Name; + class PDFFont : public RefCounted { public: static PDFErrorOr> create(Document*, NonnullRefPtr const&, float font_size); diff --git a/Userland/Libraries/LibPDF/Fonts/TrueTypeFont.cpp b/Userland/Libraries/LibPDF/Fonts/TrueTypeFont.cpp index 2e61285446..e764c7ec6a 100644 --- a/Userland/Libraries/LibPDF/Fonts/TrueTypeFont.cpp +++ b/Userland/Libraries/LibPDF/Fonts/TrueTypeFont.cpp @@ -25,7 +25,7 @@ PDFErrorOr TrueTypeFont::initialize(Document* document, NonnullRefPtrget_dict(document, CommonNames::FontDescriptor)); if (descriptor->contains(CommonNames::FontFile2)) { auto font_file_stream = TRY(descriptor->get_stream(document, CommonNames::FontFile2)); - auto ttf_font = TRY(OpenType::Font::try_load_from_externally_owned_memory(font_file_stream->bytes())); + auto ttf_font = TRY(OpenType::Font::try_load_from_externally_owned_memory(font_file_stream->bytes(), { .skip_tables = pdf_skipped_opentype_tables })); float point_size = (font_size * POINTS_PER_INCH) / DEFAULT_DPI; m_font = adopt_ref(*new Gfx::ScaledFont(*ttf_font, point_size, point_size)); } diff --git a/Userland/Libraries/LibPDF/Fonts/Type0Font.cpp b/Userland/Libraries/LibPDF/Fonts/Type0Font.cpp index 18881db15d..855444812f 100644 --- a/Userland/Libraries/LibPDF/Fonts/Type0Font.cpp +++ b/Userland/Libraries/LibPDF/Fonts/Type0Font.cpp @@ -183,7 +183,7 @@ PDFErrorOr> CIDFontType2::create(Document* document, if (descriptor->contains(CommonNames::FontFile2)) { auto font_file_stream = TRY(descriptor->get_stream(document, CommonNames::FontFile2)); float point_size = (font_size * POINTS_PER_INCH) / DEFAULT_DPI; - auto ttf_font = TRY(OpenType::Font::try_load_from_externally_owned_memory(font_file_stream->bytes(), { .external_cmap = move(cid_to_gid_map) })); + auto ttf_font = TRY(OpenType::Font::try_load_from_externally_owned_memory(font_file_stream->bytes(), { .external_cmap = move(cid_to_gid_map), .skip_tables = pdf_skipped_opentype_tables })); font = adopt_ref(*new Gfx::ScaledFont(*ttf_font, point_size, point_size)); }