mirror of
https://github.com/SerenityOS/serenity.git
synced 2026-11-07 04:29:30 -10:00
LibPDF: Move text rendering strategy selection into SimpleFont
Seems a little neater. This excludes Type0Fonts for now, but it looks like not much of the implementation would be shared. No behaviour change intended.
This commit is contained in:
1 parent
1892b09b9f
commit
4bd3d4bf95
5 files changed
+46
-38
No files matched your search
@@ -36,10 +36,6 @@ public:
|
||||
|
||||
virtual void set_font_size(float font_size) = 0;
|
||||
virtual PDFErrorOr<Gfx::FloatPoint> draw_string(Gfx::Painter&, Gfx::FloatPoint, ByteString const&, Renderer const&) = 0;
|
||||
virtual PDFErrorOr<Gfx::FloatPoint> append_text_path(Gfx::Path&, Gfx::FloatPoint, ByteString const&, Renderer const&)
|
||||
{
|
||||
return Error { Error::Type::RenderingUnsupported, "append_text_path not implemented for font" };
|
||||
}
|
||||
|
||||
virtual WritingMode writing_mode() const { return WritingMode::Horizontal; }
|
||||
|
||||
|
||||
@@ -100,6 +100,36 @@ PDFErrorOr<Gfx::FloatPoint> SimpleFont::append_text_path(Gfx::Path& path, Gfx::F
|
||||
}
|
||||
|
||||
PDFErrorOr<Gfx::FloatPoint> SimpleFont::draw_string(Gfx::Painter& painter, Gfx::FloatPoint position, ByteString const& string, Renderer const& renderer)
|
||||
{
|
||||
auto const& text_rendering_matrix = renderer.calculate_text_rendering_matrix();
|
||||
// Fast path: Use cached bitmap glyphs.
|
||||
if (text_rendering_matrix.is_identity_or_translation_or_scale(Gfx::AffineTransform::AllowNegativeScaling::Yes))
|
||||
return draw_axis_aligned_glyphs(painter, position, string, renderer);
|
||||
// Slow path: Create a Gfx::Path for the string, transform it, then draw it. This handles arbitrary transforms.
|
||||
if (auto end_position = draw_transformed_glyphs(painter, position, string, renderer); !end_position.is_error())
|
||||
return end_position;
|
||||
// Fallback to axis aligned glyphs in case `append_path` is unimplemented. This won't look correct.
|
||||
return draw_axis_aligned_glyphs(painter, position, string, renderer);
|
||||
}
|
||||
|
||||
PDFErrorOr<Gfx::FloatPoint> SimpleFont::draw_transformed_glyphs(Gfx::Painter& painter, Gfx::FloatPoint position, ByteString const& string, Renderer const& renderer)
|
||||
{
|
||||
Gfx::Path text_path;
|
||||
Gfx::AntiAliasingPainter aa_painter(painter);
|
||||
auto horizontal_scaling = renderer.text_state().horizontal_scaling;
|
||||
auto text_rendering_matrix = renderer.calculate_text_rendering_matrix();
|
||||
auto end_position = TRY(append_text_path(text_path, position, string, renderer));
|
||||
// FIXME: This is a bit janky, but the font is already scaled by `m_text_rendering_matrix.x_scale() / horizontal_scaling`,
|
||||
// which is included in `m_text_rendering_matrix`. So, we must scale it by the reciprocal. Also, the y-axis is flipped.
|
||||
text_path.transform(text_rendering_matrix.multiply(
|
||||
Gfx::AffineTransform {}
|
||||
.set_scale(1 / text_rendering_matrix.x_scale() * horizontal_scaling,
|
||||
-1 / text_rendering_matrix.x_scale() * horizontal_scaling)));
|
||||
Renderer::fill_path_with_style(aa_painter, text_path, renderer.state().paint_style, renderer.state().paint_alpha_constant);
|
||||
return end_position;
|
||||
}
|
||||
|
||||
PDFErrorOr<Gfx::FloatPoint> SimpleFont::draw_axis_aligned_glyphs(Gfx::Painter& painter, Gfx::FloatPoint position, ByteString const& string, Renderer const& renderer)
|
||||
{
|
||||
auto horizontal_scaling = renderer.text_state().horizontal_scaling;
|
||||
auto const& text_rendering_matrix = renderer.calculate_text_rendering_matrix();
|
||||
@@ -110,5 +140,4 @@ PDFErrorOr<Gfx::FloatPoint> SimpleFont::draw_string(Gfx::Painter& painter, Gfx::
|
||||
return draw_glyph(painter, glyph_render_position, glyph_width, char_code, renderer);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,12 +14,12 @@ namespace PDF {
|
||||
class SimpleFont : public PDFFont {
|
||||
public:
|
||||
PDFErrorOr<Gfx::FloatPoint> draw_string(Gfx::Painter&, Gfx::FloatPoint, ByteString const&, Renderer const&) override;
|
||||
PDFErrorOr<Gfx::FloatPoint> append_text_path(Gfx::Path&, Gfx::FloatPoint, ByteString const&, Renderer const&) override;
|
||||
|
||||
protected:
|
||||
PDFErrorOr<void> initialize(Document* document, NonnullRefPtr<DictObject> const& dict, float font_size) override;
|
||||
virtual Optional<float> get_glyph_width(u8 char_code) const = 0;
|
||||
virtual PDFErrorOr<void> draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint point, float width, u8 char_code, Renderer const&) = 0;
|
||||
|
||||
virtual PDFErrorOr<void> append_glyph_path(Gfx::Path&, Gfx::FloatPoint, u8, Renderer const&)
|
||||
{
|
||||
return Error { Error::Type::RenderingUnsupported, "append_glyph_path not implemented for font" };
|
||||
@@ -34,6 +34,10 @@ private:
|
||||
template<typename Callback>
|
||||
PDFErrorOr<Gfx::FloatPoint> for_each_glyph_position(Gfx::FloatPoint, ByteString const&, Renderer const&, Callback callback);
|
||||
|
||||
PDFErrorOr<Gfx::FloatPoint> append_text_path(Gfx::Path&, Gfx::FloatPoint, ByteString const&, Renderer const&);
|
||||
PDFErrorOr<Gfx::FloatPoint> draw_transformed_glyphs(Gfx::Painter&, Gfx::FloatPoint, ByteString const&, Renderer const&);
|
||||
PDFErrorOr<Gfx::FloatPoint> draw_axis_aligned_glyphs(Gfx::Painter&, Gfx::FloatPoint, ByteString const&, Renderer const&);
|
||||
|
||||
RefPtr<Encoding> m_encoding;
|
||||
RefPtr<StreamObject> m_to_unicode;
|
||||
HashMap<u8, u16> m_widths;
|
||||
|
||||
@@ -451,20 +451,11 @@ void Renderer::stroke_current_path()
|
||||
}
|
||||
}
|
||||
|
||||
static void do_fill_path(Gfx::AntiAliasingPainter& painter, Gfx::Path const& path, ColorOrStyle const& style, float paint_style_opacity = 1.0f, Gfx::WindingRule winding_rule = Gfx::WindingRule::Nonzero)
|
||||
{
|
||||
if (auto* paint_style = style.get_pointer<NonnullRefPtr<Gfx::PaintStyle>>()) {
|
||||
painter.fill_path(path, *paint_style, paint_style_opacity, winding_rule);
|
||||
} else {
|
||||
painter.fill_path(path, style.get<Color>(), winding_rule);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::fill_current_path(Gfx::WindingRule winding_rule)
|
||||
{
|
||||
auto path_end = m_current_path.end();
|
||||
m_current_path.close_all_subpaths();
|
||||
do_fill_path(anti_aliasing_painter(), m_current_path, state().paint_style, state().paint_alpha_constant, winding_rule);
|
||||
fill_path_with_style(anti_aliasing_painter(), m_current_path, state().paint_style, state().paint_alpha_constant, winding_rule);
|
||||
// .close_all_subpaths() only adds to the end of the path, so we can .trim() the path to remove any changes.
|
||||
m_current_path.trim(path_end);
|
||||
}
|
||||
@@ -1380,28 +1371,7 @@ PDFErrorOr<void> Renderer::show_text(ByteString const& string)
|
||||
return Error::rendering_unsupported_error("Can't draw text because an invalid font was in use");
|
||||
|
||||
auto start_position = Gfx::FloatPoint { 0.0f, 0.0f };
|
||||
auto end_position = start_position;
|
||||
|
||||
if (m_text_rendering_matrix.is_identity_or_translation_or_scale(Gfx::AffineTransform::AllowNegativeScaling::No)) {
|
||||
// Fast path: Use cached bitmap glyphs.
|
||||
end_position = TRY(text_state().font->draw_string(painter(), start_position, string, *this));
|
||||
} else {
|
||||
Gfx::Path text_path;
|
||||
// Slow path: Create a Gfx::Path for the string, transform it, then draw it. This handles arbitrary transforms.
|
||||
if (auto maybe_end = text_state().font->append_text_path(text_path, start_position, string, *this); !maybe_end.is_error()) {
|
||||
end_position = maybe_end.release_value();
|
||||
// FIXME: This is a bit janky, but the font is already scaled by `m_text_rendering_matrix.x_scale() / horizontal_scaling`,
|
||||
// which is included in `m_text_rendering_matrix`. So, we must scale it by the reciprocal. Also, the y-axis is flipped.
|
||||
text_path.transform(m_text_rendering_matrix.multiply(
|
||||
Gfx::AffineTransform {}
|
||||
.set_scale(1 / m_text_rendering_matrix.x_scale() * text_state().horizontal_scaling,
|
||||
-1 / m_text_rendering_matrix.x_scale() * text_state().horizontal_scaling)));
|
||||
do_fill_path(anti_aliasing_painter(), text_path, state().paint_style, state().paint_alpha_constant);
|
||||
} else {
|
||||
// Fallback to the fast path in case `append_path` is unimplemented.
|
||||
end_position = TRY(text_state().font->draw_string(painter(), start_position, string, *this));
|
||||
}
|
||||
}
|
||||
auto end_position = TRY(text_state().font->draw_string(painter(), start_position, string, *this));
|
||||
|
||||
// Update text matrix.
|
||||
auto delta = end_position - start_position;
|
||||
|
||||
@@ -179,6 +179,15 @@ public:
|
||||
|
||||
bool show_hidden_text() const { return m_rendering_preferences.show_hidden_text; }
|
||||
|
||||
static void fill_path_with_style(Gfx::AntiAliasingPainter& painter, Gfx::Path const& path, ColorOrStyle const& style, float paint_style_opacity = 1.0f, Gfx::WindingRule winding_rule = Gfx::WindingRule::Nonzero)
|
||||
{
|
||||
if (auto* paint_style = style.get_pointer<NonnullRefPtr<Gfx::PaintStyle>>()) {
|
||||
painter.fill_path(path, *paint_style, paint_style_opacity, winding_rule);
|
||||
} else {
|
||||
painter.fill_path(path, style.get<Color>(), winding_rule);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Renderer(RefPtr<Document>, Page const&, RefPtr<Gfx::Bitmap>, Color background_color, RenderingPreferences);
|
||||
|
||||
|
||||
Reference in new issue
Block a user