From d55867e563600c56f0e9d68c738e0d25cc2c13ee Mon Sep 17 00:00:00 2001 From: MacDue Date: Tue, 16 Jan 2024 20:32:26 +0000 Subject: [PATCH] LibPDF: Fix paths with negatively sized `re` (rect) commands Turns out the width/height in a `re` command can be negative. This results in rectangles with different winding orders. For example, a negative width results in a reversed winding order. Previously, this was lost by passing the rect through an `AffineTransform` before constructing the path. So instead, this constructs the rect path, and then transforms the resulting path. --- Userland/Libraries/LibPDF/Renderer.cpp | 10 +++++++++- Userland/Libraries/LibPDF/Renderer.h | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibPDF/Renderer.cpp b/Userland/Libraries/LibPDF/Renderer.cpp index 7d95eac830..04cd6f9a70 100644 --- a/Userland/Libraries/LibPDF/Renderer.cpp +++ b/Userland/Libraries/LibPDF/Renderer.cpp @@ -283,7 +283,10 @@ RENDERER_HANDLER(path_close) RENDERER_HANDLER(path_append_rect) { auto rect = Gfx::FloatRect(args[0].to_float(), args[1].to_float(), args[2].to_float(), args[3].to_float()); - rect_path(m_current_path, map(rect)); + // Note: The path of the rectangle is mapped (rather than the rectangle). + // This is because negative width/heights are possible, and result in different + // winding orders, but this is lost by Gfx::AffineTransform::map(). + m_current_path.append_path(map(rect_path(rect))); return {}; } @@ -933,6 +936,11 @@ Gfx::Rect Renderer::map(Gfx::Rect rect) const return state().ctm.map(rect); } +Gfx::Path Renderer::map(Gfx::Path const& path) const +{ + return path.copy_transformed(state().ctm); +} + PDFErrorOr Renderer::set_graphics_state_from_dict(NonnullRefPtr dict) { // ISO 32000 (PDF 2.0), 8.4.5 Graphics state parameter dictionaries diff --git a/Userland/Libraries/LibPDF/Renderer.h b/Userland/Libraries/LibPDF/Renderer.h index 827fe0b70b..177679dd4e 100644 --- a/Userland/Libraries/LibPDF/Renderer.h +++ b/Userland/Libraries/LibPDF/Renderer.h @@ -155,6 +155,8 @@ private: template ALWAYS_INLINE Gfx::Rect map(Gfx::Rect) const; + Gfx::Path map(Gfx::Path const&) const; + Gfx::AffineTransform calculate_image_space_transformation(int width, int height); PDFErrorOr> get_font(FontCacheKey const&);