1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 03:57:44 +00:00

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<float>, 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.
This commit is contained in:
Nico Weber 2023-10-22 23:34:14 -04:00 committed by Tim Flynn
parent 52afa936c4
commit 11bee7a075
6 changed files with 12 additions and 8 deletions

View file

@ -53,8 +53,10 @@ PDFErrorOr<Gfx::FloatPoint> 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);

View file

@ -17,7 +17,7 @@ public:
protected:
PDFErrorOr<void> initialize(Document* document, NonnullRefPtr<DictObject> const& dict, float font_size) override;
virtual float get_glyph_width(u8 char_code) const = 0;
virtual Optional<float> 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>& encoding() { return m_encoding; }
RefPtr<Encoding> const& encoding() const { return m_encoding; }
@ -26,7 +26,7 @@ private:
RefPtr<Encoding> m_encoding;
RefPtr<StreamObject> m_to_unicode;
HashMap<u8, u16> m_widths;
u16 m_missing_width;
u16 m_missing_width { 0 };
};
}

View file

@ -35,7 +35,7 @@ PDFErrorOr<void> TrueTypeFont::initialize(Document* document, NonnullRefPtr<Dict
return {};
}
float TrueTypeFont::get_glyph_width(u8 char_code) const
Optional<float> TrueTypeFont::get_glyph_width(u8 char_code) const
{
return m_font->glyph_width(char_code);
}

View file

@ -14,7 +14,7 @@ namespace PDF {
class TrueTypeFont : public SimpleFont {
public:
float get_glyph_width(u8 char_code) const override;
Optional<float> 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; }

View file

@ -49,9 +49,11 @@ PDFErrorOr<void> Type1Font::initialize(Document* document, NonnullRefPtr<DictObj
return {};
}
float Type1Font::get_glyph_width(u8 char_code) const
Optional<float> 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)

View file

@ -22,7 +22,7 @@ struct Type1GlyphCacheKey {
class Type1Font : public SimpleFont {
public:
float get_glyph_width(u8 char_code) const override;
Optional<float> 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; }