LibPDF: Apply text matrix to each glyph's position

We still don't apply it to the glyph itself, so they don't show up
scaled or rotated, but they're at the right spot now.

One big thing this here hsa going for it is that the final glyph
position is now calculated with just
`ext_rendering_matrix.map(glyph_position)`.

Also, character_spacing and word_spacing are now used unmodified
in the SimpleFont::draw_string() loop. This also means we no longer
have to undo a scale when updating the position in
`Renderer::show_text()`.

Most of the rest stays pretty yucky though. The root cause of many
problems is that ScaledFont has its rendering sized baked into the
object. We want to render fonts at size font_size times scale from
text matrix times scale from current transformation matrix (but
not size from hotizontal_scaling). So we have to make that the
font_size, but then we have to undo that in a bunch of places to
get the actualy font size.

This will eventually get better when LibPDF moves off ScaledFont.
This commit is contained in:
Nico Weber 2024-01-16 18:50:02 -05:00 committed by Andreas Kling
parent 09a91e54c0
commit d2f3288666
2 changed files with 16 additions and 11 deletions

View file

@ -51,10 +51,14 @@ PDFErrorOr<Gfx::FloatPoint> SimpleFont::draw_string(Gfx::Painter& painter, Gfx::
auto horizontal_scaling = renderer.text_state().horizontal_scaling;
auto const& text_rendering_matrix = renderer.calculate_text_rendering_matrix();
auto font_size = text_rendering_matrix.x_scale() * renderer.text_state().font_size / horizontal_scaling;
auto character_spacing = text_rendering_matrix.x_scale() * renderer.text_state().character_spacing / horizontal_scaling;
auto word_spacing = text_rendering_matrix.x_scale() * renderer.text_state().word_spacing / horizontal_scaling;
// TrueType fonts are prescaled to text_rendering_matrix.x_scale() * text_state().font_size / horizontal_scaling,
// cf `Renderer::text_set_font()`. That's the width we get back from `get_glyph_width()` if we use a fallback
// (or built-in) font. Scale the width size too, so the m_width.get() codepath is consistent.
auto const font_size = text_rendering_matrix.x_scale() * renderer.text_state().font_size / horizontal_scaling;
auto character_spacing = renderer.text_state().character_spacing;
auto word_spacing = renderer.text_state().word_spacing;
for (auto char_code : string.bytes()) {
// Use the width specified in the font's dictionary if available,
@ -67,9 +71,13 @@ PDFErrorOr<Gfx::FloatPoint> SimpleFont::draw_string(Gfx::Painter& painter, Gfx::
else
glyph_width = m_missing_width; // FIXME: times m_font_matrix.x_scale() probably?
TRY(draw_glyph(painter, glyph_position, glyph_width, char_code, renderer));
Gfx::FloatPoint glyph_render_position = text_rendering_matrix.map(glyph_position);
TRY(draw_glyph(painter, glyph_render_position, glyph_width, char_code, renderer));
auto tx = glyph_width;
// glyph_width is scaled by `text_rendering_matrix.x_scale() * renderer.text_state().font_size / horizontal_scaling`,
// but it should only be scaled by `renderer.text_state().font_size`.
// FIXME: Having to divide here isn't pretty. Refactor things so that this isn't needed.
auto tx = glyph_width / text_rendering_matrix.x_scale() * horizontal_scaling;
tx += character_spacing;
// ISO 32000 (PDF 2.0), 9.3.3 Wordspacing
@ -79,7 +87,6 @@ PDFErrorOr<Gfx::FloatPoint> SimpleFont::draw_string(Gfx::Painter& painter, Gfx::
if (char_code == ' ')
tx += word_spacing;
tx *= horizontal_scaling;
glyph_position += { tx, 0.0f };
}
return glyph_position;

View file

@ -1011,15 +1011,13 @@ PDFErrorOr<void> Renderer::show_text(ByteString const& string)
if (!text_state().font)
return Error::rendering_unsupported_error("Can't draw text because an invalid font was in use");
auto const& text_rendering_matrix = calculate_text_rendering_matrix();
auto start_position = text_rendering_matrix.map(Gfx::FloatPoint { 0.0f, 0.0f });
auto start_position = Gfx::FloatPoint { 0.0f, 0.0f };
auto end_position = TRY(text_state().font->draw_string(m_painter, start_position, string, *this));
// Update text matrix
// Update text matrix.
auto delta_x = end_position.x() - start_position.x();
m_text_rendering_matrix_is_dirty = true;
m_text_matrix.translate(delta_x / text_rendering_matrix.x_scale() * text_state().horizontal_scaling, 0.0f);
m_text_matrix.translate(delta_x * text_state().horizontal_scaling, 0.0f);
return {};
}