summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibPDF
diff options
context:
space:
mode:
authorJulian Offenhäuser <offenhaeuser@protonmail.com>2022-11-17 23:18:00 +0100
committerAndreas Kling <kling@serenityos.org>2022-11-19 11:04:34 +0100
commit7c4f5b58be6e8548a9940a6125ba09d1ee2907a0 (patch)
tree3cce0c710ce5469cf784cb06d36ca4048e3fdc98 /Userland/Libraries/LibPDF
parent0b6299849e5fabb59c3f60ac9a3ce96b86b52bb2 (diff)
downloadserenity-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.cpp52
-rw-r--r--Userland/Libraries/LibPDF/Fonts/PS1FontProgram.h6
-rw-r--r--Userland/Libraries/LibPDF/Fonts/Type1Font.cpp21
-rw-r--r--Userland/Libraries/LibPDF/Fonts/Type1Font.h1
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;
};
}