1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 13:57:35 +00:00

LibPDF: Use subpixel accurate text rendering

This just enables the new tricks from LibGfx with the same nice
improvements :^)
This commit is contained in:
MacDue 2023-01-05 01:34:07 +00:00 committed by Andreas Kling
parent 6632023498
commit 91db49f7b3
9 changed files with 24 additions and 18 deletions

View file

@ -41,7 +41,7 @@ public:
virtual u32 char_code_to_code_point(u16 char_code) const = 0; virtual u32 char_code_to_code_point(u16 char_code) const = 0;
virtual float get_char_width(u16 char_code) const = 0; virtual float get_char_width(u16 char_code) const = 0;
virtual void draw_glyph(Gfx::Painter& painter, Gfx::IntPoint point, float width, u32 char_code, Color color) = 0; virtual void draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint point, float width, u32 char_code, Color color) = 0;
virtual bool is_standard_font() const { return m_is_standard_font; } virtual bool is_standard_font() const { return m_is_standard_font; }
virtual Type type() const = 0; virtual Type type() const = 0;

View file

@ -94,15 +94,16 @@ PDFErrorOr<void> PS1FontProgram::create(ReadonlyBytes const& bytes, RefPtr<Encod
return parse_encrypted_portion(decrypted); return parse_encrypted_portion(decrypted);
} }
RefPtr<Gfx::Bitmap> PS1FontProgram::rasterize_glyph(u32 char_code, float width) RefPtr<Gfx::Bitmap> PS1FontProgram::rasterize_glyph(u32 char_code, float width, Gfx::GlyphSubpixelOffset subpixel_offset)
{ {
auto path = build_char(char_code, width); auto path = build_char(char_code, width);
auto bounding_box = path.bounding_box().size(); auto bounding_box = path.bounding_box().size();
u32 w = (u32)ceilf(bounding_box.width()) + 1; u32 w = (u32)ceilf(bounding_box.width()) + 2;
u32 h = (u32)ceilf(bounding_box.height()) + 1; u32 h = (u32)ceilf(bounding_box.height()) + 2;
Gfx::PathRasterizer rasterizer(Gfx::IntSize(w, h)); Gfx::PathRasterizer rasterizer(Gfx::IntSize(w, h));
rasterizer.translate(subpixel_offset.to_float_point());
rasterizer.draw_path(path); rasterizer.draw_path(path);
return rasterizer.accumulate(); return rasterizer.accumulate();
} }

View file

@ -8,6 +8,7 @@
#include <AK/Forward.h> #include <AK/Forward.h>
#include <LibGfx/AffineTransform.h> #include <LibGfx/AffineTransform.h>
#include <LibGfx/Font/Font.h>
#include <LibGfx/Path.h> #include <LibGfx/Path.h>
#include <LibPDF/Error.h> #include <LibPDF/Error.h>
@ -20,7 +21,7 @@ class PS1FontProgram : public RefCounted<PS1FontProgram> {
public: public:
PDFErrorOr<void> create(ReadonlyBytes const&, RefPtr<Encoding>, size_t cleartext_length, size_t encrypted_length); PDFErrorOr<void> create(ReadonlyBytes const&, RefPtr<Encoding>, size_t cleartext_length, size_t encrypted_length);
RefPtr<Gfx::Bitmap> rasterize_glyph(u32 char_code, float width); RefPtr<Gfx::Bitmap> rasterize_glyph(u32 char_code, float width, Gfx::GlyphSubpixelOffset);
Gfx::Path build_char(u32 char_code, float width); Gfx::Path build_char(u32 char_code, float width);
RefPtr<Encoding> encoding() const { return m_encoding; } RefPtr<Encoding> encoding() const { return m_encoding; }

View file

@ -68,7 +68,7 @@ float TrueTypeFont::get_char_width(u16 char_code) const
return static_cast<float>(width) / 1000.0f; return static_cast<float>(width) / 1000.0f;
} }
void TrueTypeFont::draw_glyph(Gfx::Painter& painter, Gfx::IntPoint point, float, u32 char_code, Color color) void TrueTypeFont::draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint point, float, u32 char_code, Color color)
{ {
if (!m_data.font) if (!m_data.font)
return; return;

View file

@ -24,7 +24,7 @@ public:
u32 char_code_to_code_point(u16 char_code) const override; u32 char_code_to_code_point(u16 char_code) const override;
float get_char_width(u16 char_code) const override; float get_char_width(u16 char_code) const override;
void draw_glyph(Gfx::Painter&, Gfx::IntPoint, float, u32, Color) override; void draw_glyph(Gfx::Painter&, Gfx::FloatPoint, float, u32, Color) override;
Type type() const override { return PDFFont::Type::TrueType; } Type type() const override { return PDFFont::Type::TrueType; }

View file

@ -27,7 +27,7 @@ public:
u32 char_code_to_code_point(u16 char_code) const override; u32 char_code_to_code_point(u16 char_code) const override;
float get_char_width(u16 char_code) const override; float get_char_width(u16 char_code) const override;
void draw_glyph(Gfx::Painter&, Gfx::IntPoint, float, u32, Color) override {}; void draw_glyph(Gfx::Painter&, Gfx::FloatPoint, float, u32, Color) override {};
Type type() const override { return PDFFont::Type::Type0; } Type type() const override { return PDFFont::Type::Type0; }

View file

@ -76,23 +76,26 @@ float Type1Font::get_char_width(u16 char_code) const
return static_cast<float>(width) / 1000.0f; return static_cast<float>(width) / 1000.0f;
} }
void Type1Font::draw_glyph(Gfx::Painter& painter, Gfx::IntPoint point, float width, u32 char_code, Color color) void Type1Font::draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint point, float width, u32 char_code, Color color)
{ {
if (!m_data.font_program) if (!m_data.font_program)
return; return;
auto translation = m_data.font_program->glyph_translation(char_code, width);
point = point.translated(translation);
auto glyph_position = Gfx::GlyphRasterPosition::get_nearest_fit_for(point);
Gfx::GlyphIndexWithSubpixelOffset index { char_code, glyph_position.subpixel_offset };
RefPtr<Gfx::Bitmap> bitmap; RefPtr<Gfx::Bitmap> bitmap;
auto maybe_bitmap = m_glyph_cache.get(index);
auto maybe_bitmap = m_glyph_cache.get(char_code);
if (maybe_bitmap.has_value()) { if (maybe_bitmap.has_value()) {
bitmap = maybe_bitmap.value(); bitmap = maybe_bitmap.value();
} else { } else {
bitmap = m_data.font_program->rasterize_glyph(char_code, width); bitmap = m_data.font_program->rasterize_glyph(char_code, width, glyph_position.subpixel_offset);
m_glyph_cache.set(char_code, bitmap); m_glyph_cache.set(index, bitmap);
} }
auto translation = m_data.font_program->glyph_translation(char_code, width); painter.blit_filtered(glyph_position.blit_position, *bitmap, bitmap->rect(), [color](Color pixel) -> Color {
painter.blit_filtered(point.translated(translation.to_rounded<int>()), *bitmap, bitmap->rect(), [color](Color pixel) -> Color {
return pixel.multiply(color); return pixel.multiply(color);
}); });
} }

View file

@ -6,6 +6,7 @@
#pragma once #pragma once
#include <LibGfx/Font/ScaledFont.h>
#include <LibPDF/Fonts/PDFFont.h> #include <LibPDF/Fonts/PDFFont.h>
#include <LibPDF/Fonts/PS1FontProgram.h> #include <LibPDF/Fonts/PS1FontProgram.h>
@ -27,13 +28,13 @@ public:
u32 char_code_to_code_point(u16 char_code) const override; u32 char_code_to_code_point(u16 char_code) const override;
float get_char_width(u16 char_code) const override; float get_char_width(u16 char_code) const override;
void draw_glyph(Gfx::Painter& painter, Gfx::IntPoint point, float width, u32 char_code, Color color) override; void draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint point, float width, u32 char_code, Color color) override;
Type type() const override { return PDFFont::Type::Type1; } Type type() const override { return PDFFont::Type::Type1; }
private: private:
Data m_data; Data m_data;
HashMap<u32, RefPtr<Gfx::Bitmap>> m_glyph_cache; HashMap<Gfx::GlyphIndexWithSubpixelOffset, RefPtr<Gfx::Bitmap>> m_glyph_cache;
}; };
} }

View file

@ -747,7 +747,7 @@ void Renderer::show_text(DeprecatedString const& string)
auto glyph_width = char_width * font_size; auto glyph_width = char_width * font_size;
if (code_point != 0x20) if (code_point != 0x20)
text_state().font->draw_glyph(m_painter, glyph_position.to_type<int>(), glyph_width, char_code, state().paint_color); text_state().font->draw_glyph(m_painter, glyph_position, glyph_width, char_code, state().paint_color);
auto tx = glyph_width; auto tx = glyph_width;
tx += text_state().character_spacing; tx += text_state().character_spacing;