From 11bee7a075cc72ebc9a2e5af77cb2ff46a7104e3 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Sun, 22 Oct 2023 23:34:14 -0400 Subject: [PATCH] LibPDF: Don't crash on fixed-width type 1 fonts that use /MissingWidth Type 1 fonts usually have a m_font_program and no m_font -- they only have m_font if we're using a replacement font for the fonts that were built-in to PDFs before Acrobat 4.0 (and must still work to show existing files). However, SimpleFont::get_glyph_width() used to always return a float, which in Type1Font was only implemented if m_font was set. Per spec, we're supposed to just use /MissingWidth for fonts that are missing an entry in the descriptor's /Width array. However, for built-in fonts, no explicit /Width array is needed (PDF 1.7 spec, Appendix H.3, 5.5.1). So if we just always use /MissingWidth, then PDFs that use a built-in font draw all their text on top of each other (e.g. 000333.pdf from stillhq.com-pdfdb). So change get_glyph_width() to return Optional, return it only in Type1Font if m_font is set, and use MissingWidth if it isn't set. That way, replacement fonts still return a width, and real fonts that are supposed to have /Width and use /MissingWidth for missing entries do what they're supposed to too, instead of crashing. From 20 (6%) to 16 (5%) crashes on the 300 first PDFs, and from 39 (7.8%) to 31 (6.2%) on the 500-random PDFs test. --- Userland/Libraries/LibPDF/Fonts/SimpleFont.cpp | 4 +++- Userland/Libraries/LibPDF/Fonts/SimpleFont.h | 4 ++-- Userland/Libraries/LibPDF/Fonts/TrueTypeFont.cpp | 2 +- Userland/Libraries/LibPDF/Fonts/TrueTypeFont.h | 2 +- Userland/Libraries/LibPDF/Fonts/Type1Font.cpp | 6 ++++-- Userland/Libraries/LibPDF/Fonts/Type1Font.h | 2 +- 6 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Userland/Libraries/LibPDF/Fonts/SimpleFont.cpp b/Userland/Libraries/LibPDF/Fonts/SimpleFont.cpp index f54e92a7ea..b9106c06e4 100644 --- a/Userland/Libraries/LibPDF/Fonts/SimpleFont.cpp +++ b/Userland/Libraries/LibPDF/Fonts/SimpleFont.cpp @@ -53,8 +53,10 @@ PDFErrorOr SimpleFont::draw_string(Gfx::Painter& painter, Gfx:: float glyph_width; if (auto width = m_widths.get(char_code); width.has_value()) glyph_width = font_size * width.value() / 1000.0f; + else if (auto width = get_glyph_width(char_code); width.has_value()) + glyph_width = width.value(); else - glyph_width = get_glyph_width(char_code); + glyph_width = m_missing_width; draw_glyph(painter, glyph_position, glyph_width, char_code, paint_color); diff --git a/Userland/Libraries/LibPDF/Fonts/SimpleFont.h b/Userland/Libraries/LibPDF/Fonts/SimpleFont.h index 3c8745293a..12c60cac53 100644 --- a/Userland/Libraries/LibPDF/Fonts/SimpleFont.h +++ b/Userland/Libraries/LibPDF/Fonts/SimpleFont.h @@ -17,7 +17,7 @@ public: protected: PDFErrorOr initialize(Document* document, NonnullRefPtr const& dict, float font_size) override; - virtual float get_glyph_width(u8 char_code) const = 0; + virtual Optional get_glyph_width(u8 char_code) const = 0; virtual void draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint point, float width, u8 char_code, Color color) = 0; RefPtr& encoding() { return m_encoding; } RefPtr const& encoding() const { return m_encoding; } @@ -26,7 +26,7 @@ private: RefPtr m_encoding; RefPtr m_to_unicode; HashMap m_widths; - u16 m_missing_width; + u16 m_missing_width { 0 }; }; } diff --git a/Userland/Libraries/LibPDF/Fonts/TrueTypeFont.cpp b/Userland/Libraries/LibPDF/Fonts/TrueTypeFont.cpp index 89e8baeb03..08b30a895c 100644 --- a/Userland/Libraries/LibPDF/Fonts/TrueTypeFont.cpp +++ b/Userland/Libraries/LibPDF/Fonts/TrueTypeFont.cpp @@ -35,7 +35,7 @@ PDFErrorOr TrueTypeFont::initialize(Document* document, NonnullRefPtr TrueTypeFont::get_glyph_width(u8 char_code) const { return m_font->glyph_width(char_code); } diff --git a/Userland/Libraries/LibPDF/Fonts/TrueTypeFont.h b/Userland/Libraries/LibPDF/Fonts/TrueTypeFont.h index 6abcd6e4af..5a732c5e90 100644 --- a/Userland/Libraries/LibPDF/Fonts/TrueTypeFont.h +++ b/Userland/Libraries/LibPDF/Fonts/TrueTypeFont.h @@ -14,7 +14,7 @@ namespace PDF { class TrueTypeFont : public SimpleFont { public: - float get_glyph_width(u8 char_code) const override; + Optional get_glyph_width(u8 char_code) const override; void set_font_size(float font_size) override; void draw_glyph(Gfx::Painter&, Gfx::FloatPoint, float, u8, Color) override; Type type() const override { return PDFFont::Type::TrueType; } diff --git a/Userland/Libraries/LibPDF/Fonts/Type1Font.cpp b/Userland/Libraries/LibPDF/Fonts/Type1Font.cpp index b9c4e94494..4fc379284c 100644 --- a/Userland/Libraries/LibPDF/Fonts/Type1Font.cpp +++ b/Userland/Libraries/LibPDF/Fonts/Type1Font.cpp @@ -49,9 +49,11 @@ PDFErrorOr Type1Font::initialize(Document* document, NonnullRefPtr Type1Font::get_glyph_width(u8 char_code) const { - return m_font->glyph_width(char_code); + if (m_font) + return m_font->glyph_width(char_code); + return OptionalNone {}; } void Type1Font::set_font_size(float font_size) diff --git a/Userland/Libraries/LibPDF/Fonts/Type1Font.h b/Userland/Libraries/LibPDF/Fonts/Type1Font.h index 911626f6e1..7faa3cf8b9 100644 --- a/Userland/Libraries/LibPDF/Fonts/Type1Font.h +++ b/Userland/Libraries/LibPDF/Fonts/Type1Font.h @@ -22,7 +22,7 @@ struct Type1GlyphCacheKey { class Type1Font : public SimpleFont { public: - float get_glyph_width(u8 char_code) const override; + Optional get_glyph_width(u8 char_code) const override; void set_font_size(float font_size) override; void draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint point, float width, u8 char_code, Color color) override; Type type() const override { return PDFFont::Type::Type1; }