LibPDF: Separate resolving glyph IDs from drawing glyphs

This will make reusing the logic to determine glyph IDs easier.

No behaviour change intended.
This commit is contained in:
MacDue authored and Nico Weber committed 2026-07-20 22:17:51 -04:00
1 parent 20ac70e1a6
commit e103b1ec36
5 files changed
+28 -39

No files matched your search

+1 -2
View File
@@ -30,6 +30,7 @@ public:
ScaledGlyphMetrics glyph_metrics(u32 glyph_id) const { return m_font->glyph_metrics(glyph_id, m_x_scale, m_y_scale, m_point_width, m_point_height); }
RefPtr<Gfx::Bitmap> rasterize_glyph(u32 glyph_id, GlyphSubpixelOffset) const;
bool append_glyph_path_to(Gfx::Path&, u32 glyph_id) const;
Optional<Glyph> glyph_for_id(u32 id, GlyphSubpixelOffset) const;
// ^Gfx::Font
virtual NonnullRefPtr<Font> clone() const override { return MUST(try_clone()); } // FIXME: clone() should not need to be implemented
@@ -80,8 +81,6 @@ public:
virtual bool has_color_bitmaps() const override { return m_font->has_color_bitmaps(); }
private:
Optional<Glyph> glyph_for_id(u32 id, GlyphSubpixelOffset) const;
NonnullRefPtr<VectorFont> m_font;
float m_x_scale { 0.0f };
float m_y_scale { 0.0f };
+7 -6
View File
@@ -27,6 +27,7 @@
#include <AK/Utf32View.h>
#include <AK/Utf8View.h>
#include <LibGfx/CharacterBitmap.h>
#include <LibGfx/Font/ScaledFont.h>
#include <LibGfx/Palette.h>
#include <LibGfx/Path.h>
#include <LibGfx/Quad.h>
@@ -1371,14 +1372,14 @@ FLATTEN void Painter::draw_glyph(FloatPoint point, u32 code_point, Font const& f
draw_glyph_internal(point, glyph_position, top_left, glyph, color);
}
FLATTEN void Painter::draw_glyph_with_postscript_name(FloatPoint point, StringView name, Font const& font, Color color)
FLATTEN void Painter::draw_glyph_via_glyph_id(FloatPoint point, Gfx::ScaledFont const& font, u32 glyph_id, Color color)
{
auto left_bearing = font.glyph_left_bearing_for_postscript_name(name);
if (!left_bearing.has_value())
return;
auto top_left = point + FloatPoint(left_bearing.value(), 0);
auto top_left = point + Gfx::FloatPoint(font.glyph_metrics(glyph_id).left_side_bearing, 0);
auto glyph_position = Gfx::GlyphRasterPosition::get_nearest_fit_for(top_left);
auto glyph = font.glyph_for_postscript_name(name, glyph_position.subpixel_offset).value();
auto maybe_glyph = font.glyph_for_id(glyph_id, glyph_position.subpixel_offset);
if (!maybe_glyph.has_value())
return;
auto glyph = maybe_glyph.release_value();
draw_glyph_internal(point, glyph_position, top_left, glyph, color);
}
+1 -1
View File
@@ -114,9 +114,9 @@ public:
void draw_glyph_or_emoji(IntPoint, Utf8CodePointIterator&, Font const&, Color);
void draw_glyph(FloatPoint, u32, Color);
void draw_glyph(FloatPoint, u32, Font const&, Color);
void draw_glyph_with_postscript_name(FloatPoint point, StringView name, Font const& font, Color color);
void draw_glyph_or_emoji(FloatPoint, u32, Font const&, Color);
void draw_glyph_or_emoji(FloatPoint, Utf8CodePointIterator&, Font const&, Color);
void draw_glyph_via_glyph_id(FloatPoint, Gfx::ScaledFont const&, u32, Color);
void draw_circle_arc_intersecting(IntRect const&, IntPoint, int radius, Color, int thickness);
// Streamlined text drawing routine that does no wrapping/elision/alignment.
@@ -62,40 +62,23 @@ NonnullOwnPtr<TrueTypePainter> TrueTypePainter::create(Document* document, Nonnu
return adopt_own(*new TrueTypePainter { move(font), move(encoding), encoding_is_mac_roman_or_win_ansi, containing_pdf_font.is_nonsymbolic(), high_byte, is_zapf_dingbats });
}
static void do_draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint point, float width, u32 unicode, Gfx::ScaledFont const& font, ColorOrStyle const& style)
static void do_draw_glyph(Gfx::Painter& painter, u32 glyph_id, Gfx::FloatPoint point, float width, Gfx::ScaledFont const& font, ColorOrStyle const& style)
{
// Undo shift in Glyf::Glyph::append_simple_path() via OpenType::Font::rasterize_glyph().
auto position = point.translated(0, -font.pixel_metrics().ascent);
if (style.has<Color>()) {
painter.draw_glyph(position, unicode, font, style.get<Color>());
painter.draw_glyph_via_glyph_id(position, font, glyph_id, style.get<Color>());
} else {
// FIXME: Bounding box and sample point look to be pretty wrong
style.get<NonnullRefPtr<Gfx::PaintStyle>>()->paint(Gfx::IntRect(position.x(), position.y(), width, 0), [&](auto sample) {
painter.draw_glyph(position, unicode, font, sample(Gfx::IntPoint(position.x(), position.y())));
painter.draw_glyph_via_glyph_id(position, font, glyph_id, sample(Gfx::IntPoint(position.x(), position.y())));
});
}
}
static void do_draw_glyph_with_postscript_name(Gfx::Painter& painter, Gfx::FloatPoint point, float width, StringView postscript_name, Gfx::ScaledFont const& font, ColorOrStyle const& style)
PDFErrorOr<TrueTypePainter::GlyphID> TrueTypePainter::resolve_glyph_id_for_char_code(u8 char_code)
{
// Undo shift in Glyf::Glyph::append_simple_path() via OpenType::Font::rasterize_glyph().
auto position = point.translated(0, -font.pixel_metrics().ascent);
if (style.has<Color>()) {
painter.draw_glyph_with_postscript_name(position, postscript_name, font, style.get<Color>());
} else {
// FIXME: Bounding box and sample point look to be pretty wrong
style.get<NonnullRefPtr<Gfx::PaintStyle>>()->paint(Gfx::IntRect(position.x(), position.y(), width, 0), [&](auto sample) {
painter.draw_glyph_with_postscript_name(position, postscript_name, font, sample(Gfx::IntPoint(position.x(), position.y())));
});
}
}
PDFErrorOr<void> TrueTypePainter::draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint point, float width, u8 char_code, Renderer const& renderer)
{
auto style = renderer.state().paint_style;
// 5.5.5 Character Encoding, Encodings for TrueType Fonts
u32 unicode;
@@ -126,17 +109,13 @@ PDFErrorOr<void> TrueTypePainter::draw_glyph(Gfx::Painter& painter, Gfx::FloatPo
// FIXME: Implement (1, 0) subtable support.
auto char_name = m_encoding->get_name(char_code);
u32 unicode = glyph_name_to_unicode(char_name, m_is_zapf_dingbats).value_or(char_code);
if (m_font->contains_glyph(unicode)) {
do_draw_glyph(painter, point, width, unicode, *m_font, style);
return {};
}
if (m_font->contains_glyph(unicode))
return m_font->glyph_id_for_code_point(unicode);
// "In either of the cases above, if the glyph name cannot be mapped as specified, the glyph name is looked up
// in the font program’s “post” table (if one is present) and the associated glyph description is used."
if (m_font->contains_glyph_for_postscript_name(char_name)) {
do_draw_glyph_with_postscript_name(painter, point, width, char_name, *m_font, style);
return {};
}
if (m_font->contains_glyph_for_postscript_name(char_name))
return m_font->glyph_id_for_postscript_name(char_name);
return Error::malformed_error("Failed to draw glyph with postscript name");
} else if (m_high_byte.has_value()) {
@@ -158,7 +137,14 @@ PDFErrorOr<void> TrueTypePainter::draw_glyph(Gfx::Painter& painter, Gfx::FloatPo
unicode = glyph_name_to_unicode(char_name, m_is_zapf_dingbats).value_or(char_code);
}
do_draw_glyph(painter, point, width, unicode, *m_font, style);
return m_font->glyph_id_for_code_point(unicode);
}
PDFErrorOr<void> TrueTypePainter::draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint point, float width, u8 char_code, Renderer const& renderer)
{
auto glyph_id = TRY(resolve_glyph_id_for_char_code(char_code));
if (glyph_id.has_value())
do_draw_glyph(painter, *glyph_id, point, width, m_font, renderer.state().paint_style);
return {};
}
@@ -23,6 +23,9 @@ public:
private:
TrueTypePainter(AK::NonnullRefPtr<Gfx::ScaledFont>, NonnullRefPtr<Encoding>, bool encoding_is_mac_roman_or_win_ansi, bool is_nonsymbolic, Optional<u8> high_byte, bool is_zapf_dingbats);
using GlyphID = Optional<u32>;
PDFErrorOr<GlyphID> resolve_glyph_id_for_char_code(u8 char_code);
NonnullRefPtr<Gfx::ScaledFont> m_font;
NonnullRefPtr<Encoding> m_encoding;
bool m_encoding_is_mac_roman_or_win_ansi { false };