diff options
author | Julian Offenhäuser <offenhaeuser@protonmail.com> | 2022-11-17 23:18:00 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-11-19 11:04:34 +0100 |
commit | 7c4f5b58be6e8548a9940a6125ba09d1ee2907a0 (patch) | |
tree | 3cce0c710ce5469cf784cb06d36ca4048e3fdc98 /Userland/Libraries/LibPDF | |
parent | 0b6299849e5fabb59c3f60ac9a3ce96b86b52bb2 (diff) | |
download | serenity-7c4f5b58be6e8548a9940a6125ba09d1ee2907a0.zip |
LibPDF: Use Gfx::PathRasterizer for Adobe Type 1 font rendering
This gives much better visual results than painting the path directly.
It also has the nice side effect that Type 1 fonts will now look much
more similar to TrueType fonts, which use the same class :^)
In addition, we can now cache glyph bitmaps for repeated use.
Diffstat (limited to 'Userland/Libraries/LibPDF')
-rw-r--r-- | Userland/Libraries/LibPDF/Fonts/PS1FontProgram.cpp | 52 | ||||
-rw-r--r-- | Userland/Libraries/LibPDF/Fonts/PS1FontProgram.h | 6 | ||||
-rw-r--r-- | Userland/Libraries/LibPDF/Fonts/Type1Font.cpp | 21 | ||||
-rw-r--r-- | Userland/Libraries/LibPDF/Fonts/Type1Font.h | 1 |
4 files changed, 69 insertions, 11 deletions
diff --git a/Userland/Libraries/LibPDF/Fonts/PS1FontProgram.cpp b/Userland/Libraries/LibPDF/Fonts/PS1FontProgram.cpp index b4d15f1291..cb266f44fe 100644 --- a/Userland/Libraries/LibPDF/Fonts/PS1FontProgram.cpp +++ b/Userland/Libraries/LibPDF/Fonts/PS1FontProgram.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include <LibGfx/Font/PathRasterizer.h> #include <LibPDF/CommonNames.h> #include <LibPDF/Encoding.h> #include <LibPDF/Fonts/PS1FontProgram.h> @@ -86,20 +87,61 @@ PDFErrorOr<void> PS1FontProgram::parse(ReadonlyBytes const& bytes, size_t cleart return parse_encrypted_portion(decrypted); } -Gfx::Path PS1FontProgram::build_char(u32 code_point, Gfx::FloatPoint const& point, float width) +RefPtr<Gfx::Bitmap> PS1FontProgram::rasterize_glyph(u32 code_point, float width) { - if (!m_glyph_map.contains(code_point)) + auto path = build_char(code_point, width); + auto bounding_box = path.bounding_box().size(); + + u32 w = (u32)ceilf(bounding_box.width()) + 1; + u32 h = (u32)ceilf(bounding_box.height()) + 1; + + Gfx::PathRasterizer rasterizer(Gfx::IntSize(w, h)); + rasterizer.draw_path(path); + return rasterizer.accumulate(); +} + +Gfx::Path PS1FontProgram::build_char(u32 code_point, float width) +{ + auto maybe_glyph = m_glyph_map.get(code_point); + if (!maybe_glyph.has_value()) return {}; - auto glyph = m_glyph_map.get(code_point).value(); + auto& glyph = maybe_glyph.value(); + auto transform = glyph_transform_to_device_space(glyph, width); + + // Translate such that the top-left point is at [0, 0]. + auto bounding_box = glyph.path.bounding_box(); + Gfx::FloatPoint translation(-bounding_box.x(), -(bounding_box.y() + bounding_box.height())); + transform.translate(translation); + + return glyph.path.copy_transformed(transform); +} + +Gfx::FloatPoint PS1FontProgram::glyph_translation(u32 code_point, float width) const +{ + auto maybe_glyph = m_glyph_map.get(code_point); + if (!maybe_glyph.has_value()) + return {}; + + auto& glyph = maybe_glyph.value(); + auto transform = glyph_transform_to_device_space(glyph, width); + + // Undo the translation we applied earlier. + auto bounding_box = glyph.path.bounding_box(); + Gfx::FloatPoint translation(bounding_box.x(), bounding_box.y() + bounding_box.height()); + + return transform.map(translation); +} + +Gfx::AffineTransform PS1FontProgram::glyph_transform_to_device_space(Glyph const& glyph, float width) const +{ auto scale = width / (m_font_matrix.a() * glyph.width + m_font_matrix.e()); auto transform = m_font_matrix; // Convert character space to device space. transform.scale(scale, -scale); - transform.set_translation(point); - return glyph.path.copy_transformed(transform); + return transform; } PDFErrorOr<PS1FontProgram::Glyph> PS1FontProgram::parse_glyph(ReadonlyBytes const& data, GlyphParserState& state) diff --git a/Userland/Libraries/LibPDF/Fonts/PS1FontProgram.h b/Userland/Libraries/LibPDF/Fonts/PS1FontProgram.h index b119f2f19b..0a8afa733d 100644 --- a/Userland/Libraries/LibPDF/Fonts/PS1FontProgram.h +++ b/Userland/Libraries/LibPDF/Fonts/PS1FontProgram.h @@ -20,9 +20,11 @@ class PS1FontProgram : public RefCounted<PS1FontProgram> { public: PDFErrorOr<void> parse(ReadonlyBytes const&, size_t cleartext_length, size_t encrypted_length); - Gfx::Path build_char(u32 code_point, Gfx::FloatPoint const& point, float width); + RefPtr<Gfx::Bitmap> rasterize_glyph(u32 code_point, float width); + Gfx::Path build_char(u32 code_point, float width); RefPtr<Encoding> encoding() const { return m_encoding; } + Gfx::FloatPoint glyph_translation(u32 code_point, float width) const; private: struct Glyph { @@ -46,6 +48,8 @@ private: Array<float, 24> postscript_stack; }; + Gfx::AffineTransform glyph_transform_to_device_space(Glyph const&, float width) const; + PDFErrorOr<Glyph> parse_glyph(ReadonlyBytes const&, GlyphParserState&); PDFErrorOr<void> parse_encrypted_portion(ByteBuffer const&); PDFErrorOr<Vector<ByteBuffer>> parse_subroutines(Reader&); diff --git a/Userland/Libraries/LibPDF/Fonts/Type1Font.cpp b/Userland/Libraries/LibPDF/Fonts/Type1Font.cpp index ac15a8837f..e580fe8ada 100644 --- a/Userland/Libraries/LibPDF/Fonts/Type1Font.cpp +++ b/Userland/Libraries/LibPDF/Fonts/Type1Font.cpp @@ -122,11 +122,22 @@ float Type1Font::get_char_width(u16 char_code, float) const void Type1Font::draw_glyph(Gfx::Painter& painter, Gfx::IntPoint const& point, float width, u32 code_point, Color color) { - // FIXME: Make a glyph cache - if (m_data.font_program) { - auto path = m_data.font_program->build_char(code_point, { point.x(), point.y() }, width); - Gfx::AntiAliasingPainter aa_painter(painter); - aa_painter.fill_path(path, color, Gfx::Painter::WindingRule::EvenOdd); + if (!m_data.font_program) + return; + + RefPtr<Gfx::Bitmap> bitmap; + + auto maybe_bitmap = m_glyph_cache.get(code_point); + if (maybe_bitmap.has_value()) { + bitmap = maybe_bitmap.value(); + } else { + bitmap = m_data.font_program->rasterize_glyph(code_point, width); + m_glyph_cache.set(code_point, bitmap); } + + auto translation = m_data.font_program->glyph_translation(code_point, width); + painter.blit_filtered(point.translated(translation.to_rounded<int>()), *bitmap, bitmap->rect(), [color](Color pixel) -> Color { + return pixel.multiply(color); + }); } } diff --git a/Userland/Libraries/LibPDF/Fonts/Type1Font.h b/Userland/Libraries/LibPDF/Fonts/Type1Font.h index cc44e3076e..ce875d27dc 100644 --- a/Userland/Libraries/LibPDF/Fonts/Type1Font.h +++ b/Userland/Libraries/LibPDF/Fonts/Type1Font.h @@ -40,6 +40,7 @@ public: private: Data m_data; + HashMap<u32, RefPtr<Gfx::Bitmap>> m_glyph_cache; }; } |