From 29396415d58b0775d2ca1360362966c75dc4d255 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 15 Nov 2023 07:51:56 -0500 Subject: [PATCH] LibPDF: Add an initial implementation of type 3 glyph rendering This is a very inefficient implementation: Every time a type 3 font glyph is drawn, we parse its operator stream and execute all the operators therein. We'll want to instead cache the glyphs in bitmaps (at least in most cases), like we do for other fonts. But it's a good first step, and all the coordinate math seems to work in the files I've tested. Good test files from pdfa dataset 0000.zip: - 0000559.pdf page 1 (and 2): Has a non-default font matrix; text appears mirrored if the font matrix isn't handled correctly - 0000425.pdf, page 1: Draws several glyphs in a single run; glyphs overlap if Renderer::render_type3_glyph() ignores the passed-in point - 0000211.pdf, any page: Uses type 3 glyphs for all text. Good perf test (already "reasonably fast") - 0000521.pdf, page 5 (or 7 or or 16): The little red flag in the purple box is a type 3 font glyph, and it's colored (which in part means the first operator is `d0`, while all the other documents above use `d1`) --- Userland/Libraries/LibPDF/Fonts/Type3Font.cpp | 10 ++++++---- Userland/Libraries/LibPDF/Renderer.cpp | 17 +++++++++++++++++ Userland/Libraries/LibPDF/Renderer.h | 3 +++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Userland/Libraries/LibPDF/Fonts/Type3Font.cpp b/Userland/Libraries/LibPDF/Fonts/Type3Font.cpp index 1cc3f14203..9ff43766b7 100644 --- a/Userland/Libraries/LibPDF/Fonts/Type3Font.cpp +++ b/Userland/Libraries/LibPDF/Fonts/Type3Font.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace PDF { @@ -53,7 +54,7 @@ void Type3Font::set_font_size(float) { } -PDFErrorOr Type3Font::draw_glyph(Gfx::Painter&, Gfx::FloatPoint, float, u8 char_code, Renderer const&) +PDFErrorOr Type3Font::draw_glyph(Gfx::Painter&, Gfx::FloatPoint point, float, u8 char_code, Renderer const& renderer) { // PDF 1.7 spec, 5.5.4 Type 3 Fonts: // "For each character code shown by a text-showing operator that uses a Type 3 font, @@ -71,8 +72,9 @@ PDFErrorOr Type3Font::draw_glyph(Gfx::Painter&, Gfx::FloatPoint, float, u8 return {}; // "3. Invokes the glyph description, as described below." - // FIXME - - return Error { Error::Type::RenderingUnsupported, "Type3 fonts not yet implemented" }; + // The Gfx::Painter isn't used because `renderer` paints to it already. + // FIXME: Do color things dependent on if the glyph data starts with d0 or d1. + // FIXME: Glyph caching. + return const_cast(renderer).render_type3_glyph(point, *char_proc.value(), font_matrix(), m_resources); } } diff --git a/Userland/Libraries/LibPDF/Renderer.cpp b/Userland/Libraries/LibPDF/Renderer.cpp index b2ef3abc3a..1b36eed0da 100644 --- a/Userland/Libraries/LibPDF/Renderer.cpp +++ b/Userland/Libraries/LibPDF/Renderer.cpp @@ -1008,4 +1008,21 @@ Gfx::AffineTransform const& Renderer::calculate_text_rendering_matrix() const return m_text_rendering_matrix; } +PDFErrorOr Renderer::render_type3_glyph(Gfx::FloatPoint point, StreamObject const& glyph_data, Gfx::AffineTransform const& font_matrix, Optional> resources) +{ + ScopedState scoped_state { *this }; + + auto text_rendering_matrix = calculate_text_rendering_matrix(); + text_rendering_matrix.set_translation(point); + state().ctm = text_rendering_matrix; + state().ctm.scale(text_state().font_size, text_state().font_size); + state().ctm.multiply(font_matrix); + m_text_rendering_matrix_is_dirty = true; + + auto operators = TRY(Parser::parse_operators(m_document, glyph_data.bytes())); + for (auto& op : operators) + TRY(handle_operator(op, resources)); + return {}; +} + } diff --git a/Userland/Libraries/LibPDF/Renderer.h b/Userland/Libraries/LibPDF/Renderer.h index 02a174046b..c135593b4a 100644 --- a/Userland/Libraries/LibPDF/Renderer.h +++ b/Userland/Libraries/LibPDF/Renderer.h @@ -111,6 +111,9 @@ public: ALWAYS_INLINE TextState const& text_state() const { return state().text_state; } Gfx::AffineTransform const& calculate_text_rendering_matrix() const; + + PDFErrorOr render_type3_glyph(Gfx::FloatPoint, StreamObject const&, Gfx::AffineTransform const&, Optional>); + private: Renderer(RefPtr, Page const&, RefPtr, RenderingPreferences);