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.
This commit is contained in:
Nico Weber 2024-02-20 11:31:33 -05:00 committed by Andreas Kling
parent 41eca52b50
commit 5efe80af7f
Notes: sideshowbarker 2024-07-16 23:38:54 +09:00
5 changed files with 31 additions and 11 deletions

View File

@ -256,9 +256,12 @@ ErrorOr<NonnullRefPtr<Font>> 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> 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

View File

@ -30,6 +30,12 @@ public:
struct FontOptions {
unsigned index { 0 };
OwnPtr<CharCodeToGlyphIndex> 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>&& 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<Name> m_name;
Hhea m_hhea;
Maxp m_maxp;
Hmtx m_hmtx;

View File

@ -8,6 +8,7 @@
#include <AK/HashMap.h>
#include <AK/Tuple.h>
#include <LibGfx/Font/OpenType/Font.h>
#include <LibGfx/Forward.h>
#include <LibPDF/Document.h>
#include <LibPDF/Encoding.h>
@ -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<PDFFont> {
public:
static PDFErrorOr<NonnullRefPtr<PDFFont>> create(Document*, NonnullRefPtr<DictObject> const&, float font_size);

View File

@ -25,7 +25,7 @@ PDFErrorOr<void> TrueTypeFont::initialize(Document* document, NonnullRefPtr<Dict
auto descriptor = MUST(dict->get_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));
}

View File

@ -183,7 +183,7 @@ PDFErrorOr<NonnullOwnPtr<CIDFontType2>> 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));
}