From eb97617ff0a1a4dcb759101cdc52739189ebdad7 Mon Sep 17 00:00:00 2001 From: Marcus Nilsson Date: Mon, 3 Jan 2022 00:24:11 +0100 Subject: [PATCH] PDFViewer: Add actions to rotate the displayed PDF This implements the rotate cw/ccw actions in PDFViewer. Since the rendered pages are stored in a HashMap for caching, the bitmap is wrapped in a struct with the current rotation. This way the caching works as expected while zooming, and a new bitmap is rendered when the page is rotated. --- Userland/Applications/PDFViewer/PDFViewer.cpp | 18 ++++++++++++------ Userland/Applications/PDFViewer/PDFViewer.h | 9 ++++++++- .../Applications/PDFViewer/PDFViewerWidget.cpp | 14 ++++++++++++++ .../Applications/PDFViewer/PDFViewerWidget.h | 2 ++ 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/Userland/Applications/PDFViewer/PDFViewer.cpp b/Userland/Applications/PDFViewer/PDFViewer.cpp index 3fed2b229a..ccc79e544e 100644 --- a/Userland/Applications/PDFViewer/PDFViewer.cpp +++ b/Userland/Applications/PDFViewer/PDFViewer.cpp @@ -29,7 +29,7 @@ void PDFViewer::set_document(RefPtr document) m_rendered_page_list.ensure_capacity(document->get_page_count()); for (u32 i = 0; i < document->get_page_count(); i++) - m_rendered_page_list.unchecked_append(HashMap>()); + m_rendered_page_list.unchecked_append(HashMap()); update(); } @@ -38,11 +38,11 @@ RefPtr PDFViewer::get_rendered_page(u32 index) { auto& rendered_page_map = m_rendered_page_list[index]; auto existing_rendered_page = rendered_page_map.get(m_zoom_level); - if (existing_rendered_page.has_value()) - return existing_rendered_page.value(); + if (existing_rendered_page.has_value() && existing_rendered_page.value().rotation == m_rotations) + return existing_rendered_page.value().bitmap; auto rendered_page = render_page(m_document->get_page(index)); - rendered_page_map.set(m_zoom_level, rendered_page); + rendered_page_map.set(m_zoom_level, { rendered_page, m_rotations }); return rendered_page; } @@ -167,6 +167,12 @@ void PDFViewer::reset_zoom() update(); } +void PDFViewer::rotate(int degrees) +{ + m_rotations = (m_rotations + degrees + 360) % 360; + update(); +} + RefPtr PDFViewer::render_page(const PDF::Page& page) { auto zoom_scale_factor = static_cast(zoom_levels[m_zoom_level]) / 100.0f; @@ -181,8 +187,8 @@ RefPtr PDFViewer::render_page(const PDF::Page& page) PDF::Renderer::render(*m_document, page, bitmap); - if (page.rotate != 0) { - int rotation_count = (page.rotate / 90) % 4; + if (page.rotate + m_rotations != 0) { + int rotation_count = ((page.rotate + m_rotations) / 90) % 4; if (rotation_count == 3) { bitmap = bitmap->rotated(Gfx::RotationDirection::CounterClockwise).release_value_but_fixme_should_propagate_errors(); } else { diff --git a/Userland/Applications/PDFViewer/PDFViewer.h b/Userland/Applications/PDFViewer/PDFViewer.h index 5b884b46c1..5182fca5e3 100644 --- a/Userland/Applications/PDFViewer/PDFViewer.h +++ b/Userland/Applications/PDFViewer/PDFViewer.h @@ -52,6 +52,7 @@ public: void zoom_in(); void zoom_out(); void reset_zoom(); + void rotate(int degrees); protected: PDFViewer(); @@ -64,14 +65,20 @@ protected: virtual void timer_event(Core::TimerEvent&) override; private: + struct RenderedPage { + RefPtr bitmap; + int rotation; + }; + RefPtr get_rendered_page(u32 index); RefPtr render_page(const PDF::Page&); RefPtr m_document; u32 m_current_page_index { 0 }; - Vector>> m_rendered_page_list; + Vector> m_rendered_page_list; u8 m_zoom_level { initial_zoom_level }; Gfx::IntPoint m_pan_starting_position; + int m_rotations { 0 }; }; diff --git a/Userland/Applications/PDFViewer/PDFViewerWidget.cpp b/Userland/Applications/PDFViewer/PDFViewerWidget.cpp index 618dfd63b2..dcc11b4f65 100644 --- a/Userland/Applications/PDFViewer/PDFViewerWidget.cpp +++ b/Userland/Applications/PDFViewer/PDFViewerWidget.cpp @@ -130,13 +130,25 @@ void PDFViewerWidget::create_toolbar() m_viewer->reset_zoom(); }); + m_rotate_counterclockwise_action = GUI::CommonActions::make_rotate_counterclockwise_action([&](auto&) { + m_viewer->rotate(-90); + }); + + m_rotate_clockwise_action = GUI::CommonActions::make_rotate_clockwise_action([&](auto&) { + m_viewer->rotate(90); + }); + m_zoom_in_action->set_enabled(false); m_zoom_out_action->set_enabled(false); m_reset_zoom_action->set_enabled(false); + m_rotate_counterclockwise_action->set_enabled(false); + m_rotate_clockwise_action->set_enabled(false); toolbar.add_action(*m_zoom_in_action); toolbar.add_action(*m_zoom_out_action); toolbar.add_action(*m_reset_zoom_action); + toolbar.add_action(*m_rotate_counterclockwise_action); + toolbar.add_action(*m_rotate_clockwise_action); } void PDFViewerWidget::open_file(int fd, String const& path) @@ -167,6 +179,8 @@ void PDFViewerWidget::open_file(int fd, String const& path) m_zoom_in_action->set_enabled(true); m_zoom_out_action->set_enabled(true); m_reset_zoom_action->set_enabled(true); + m_rotate_counterclockwise_action->set_enabled(true); + m_rotate_clockwise_action->set_enabled(true); if (document->outline()) { auto outline = document->outline(); diff --git a/Userland/Applications/PDFViewer/PDFViewerWidget.h b/Userland/Applications/PDFViewer/PDFViewerWidget.h index 92840d3852..b482f1876c 100644 --- a/Userland/Applications/PDFViewer/PDFViewerWidget.h +++ b/Userland/Applications/PDFViewer/PDFViewerWidget.h @@ -38,6 +38,8 @@ private: RefPtr m_zoom_in_action; RefPtr m_zoom_out_action; RefPtr m_reset_zoom_action; + RefPtr m_rotate_counterclockwise_action; + RefPtr m_rotate_clockwise_action; bool m_sidebar_open { false }; ByteBuffer m_buffer;