From fa95e5ec0e441f8f848cefd9d8dab3e9a7b03e80 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 20 Feb 2024 21:38:45 -0500 Subject: [PATCH] LibPDF: Fix line drawing when line_width is 0 We used to skip lines with width 0. The correct behavior per spec is to draw them one pixel wide instead. --- Userland/Libraries/LibPDF/Renderer.cpp | 21 +++++++++++++++------ Userland/Libraries/LibPDF/Renderer.h | 2 ++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Userland/Libraries/LibPDF/Renderer.cpp b/Userland/Libraries/LibPDF/Renderer.cpp index e6ff7dfebc..a2962f8fe8 100644 --- a/Userland/Libraries/LibPDF/Renderer.cpp +++ b/Userland/Libraries/LibPDF/Renderer.cpp @@ -327,9 +327,9 @@ RENDERER_HANDLER(path_stroke) { begin_path_paint(); if (state().stroke_style.has>()) { - m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get>(), state().ctm.x_scale() * state().line_width); + m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get>(), line_width()); } else { - m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get(), state().ctm.x_scale() * state().line_width); + m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get(), line_width()); } end_path_paint(); return {}; @@ -376,9 +376,9 @@ RENDERER_HANDLER(path_fill_evenodd) RENDERER_HANDLER(path_fill_stroke_nonzero) { if (state().stroke_style.has>()) { - m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get>(), state().ctm.x_scale() * state().line_width); + m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get>(), line_width()); } else { - m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get(), state().ctm.x_scale() * state().line_width); + m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get(), line_width()); } return handle_path_fill_nonzero(args); } @@ -386,9 +386,9 @@ RENDERER_HANDLER(path_fill_stroke_nonzero) RENDERER_HANDLER(path_fill_stroke_evenodd) { if (state().stroke_style.has>()) { - m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get>(), state().ctm.x_scale() * state().line_width); + m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get>(), line_width()); } else { - m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get(), state().ctm.x_scale() * state().line_width); + m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get(), line_width()); } return handle_path_fill_evenodd(args); } @@ -953,6 +953,15 @@ Gfx::Path Renderer::map(Gfx::Path const& path) const return path.copy_transformed(state().ctm); } +float Renderer::line_width() const +{ + // PDF 1.7 spec, 4.3.2 Details of Graphics State Parameters, Line Width: + // "A line width of 0 denotes the thinnest line that can be rendered at device resolution: 1 device pixel wide." + if (state().line_width == 0) + return 1; + return state().ctm.x_scale() * state().line_width; +} + 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 407f40fb2a..9c9d6350df 100644 --- a/Userland/Libraries/LibPDF/Renderer.h +++ b/Userland/Libraries/LibPDF/Renderer.h @@ -176,6 +176,8 @@ private: Gfx::Path map(Gfx::Path const&) const; + float line_width() const; + Gfx::AffineTransform calculate_image_space_transformation(int width, int height); PDFErrorOr> get_font(FontCacheKey const&);