1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 04:37:44 +00:00

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.
This commit is contained in:
Marcus Nilsson 2022-01-03 00:24:11 +01:00 committed by Andreas Kling
parent cecbed467b
commit eb97617ff0
4 changed files with 36 additions and 7 deletions

View file

@ -29,7 +29,7 @@ void PDFViewer::set_document(RefPtr<PDF::Document> document)
m_rendered_page_list.ensure_capacity(document->get_page_count()); m_rendered_page_list.ensure_capacity(document->get_page_count());
for (u32 i = 0; i < document->get_page_count(); i++) for (u32 i = 0; i < document->get_page_count(); i++)
m_rendered_page_list.unchecked_append(HashMap<u32, RefPtr<Gfx::Bitmap>>()); m_rendered_page_list.unchecked_append(HashMap<u32, RenderedPage>());
update(); update();
} }
@ -38,11 +38,11 @@ RefPtr<Gfx::Bitmap> PDFViewer::get_rendered_page(u32 index)
{ {
auto& rendered_page_map = m_rendered_page_list[index]; auto& rendered_page_map = m_rendered_page_list[index];
auto existing_rendered_page = rendered_page_map.get(m_zoom_level); auto existing_rendered_page = rendered_page_map.get(m_zoom_level);
if (existing_rendered_page.has_value()) if (existing_rendered_page.has_value() && existing_rendered_page.value().rotation == m_rotations)
return existing_rendered_page.value(); return existing_rendered_page.value().bitmap;
auto rendered_page = render_page(m_document->get_page(index)); 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; return rendered_page;
} }
@ -167,6 +167,12 @@ void PDFViewer::reset_zoom()
update(); update();
} }
void PDFViewer::rotate(int degrees)
{
m_rotations = (m_rotations + degrees + 360) % 360;
update();
}
RefPtr<Gfx::Bitmap> PDFViewer::render_page(const PDF::Page& page) RefPtr<Gfx::Bitmap> PDFViewer::render_page(const PDF::Page& page)
{ {
auto zoom_scale_factor = static_cast<float>(zoom_levels[m_zoom_level]) / 100.0f; auto zoom_scale_factor = static_cast<float>(zoom_levels[m_zoom_level]) / 100.0f;
@ -181,8 +187,8 @@ RefPtr<Gfx::Bitmap> PDFViewer::render_page(const PDF::Page& page)
PDF::Renderer::render(*m_document, page, bitmap); PDF::Renderer::render(*m_document, page, bitmap);
if (page.rotate != 0) { if (page.rotate + m_rotations != 0) {
int rotation_count = (page.rotate / 90) % 4; int rotation_count = ((page.rotate + m_rotations) / 90) % 4;
if (rotation_count == 3) { if (rotation_count == 3) {
bitmap = bitmap->rotated(Gfx::RotationDirection::CounterClockwise).release_value_but_fixme_should_propagate_errors(); bitmap = bitmap->rotated(Gfx::RotationDirection::CounterClockwise).release_value_but_fixme_should_propagate_errors();
} else { } else {

View file

@ -52,6 +52,7 @@ public:
void zoom_in(); void zoom_in();
void zoom_out(); void zoom_out();
void reset_zoom(); void reset_zoom();
void rotate(int degrees);
protected: protected:
PDFViewer(); PDFViewer();
@ -64,14 +65,20 @@ protected:
virtual void timer_event(Core::TimerEvent&) override; virtual void timer_event(Core::TimerEvent&) override;
private: private:
struct RenderedPage {
RefPtr<Gfx::Bitmap> bitmap;
int rotation;
};
RefPtr<Gfx::Bitmap> get_rendered_page(u32 index); RefPtr<Gfx::Bitmap> get_rendered_page(u32 index);
RefPtr<Gfx::Bitmap> render_page(const PDF::Page&); RefPtr<Gfx::Bitmap> render_page(const PDF::Page&);
RefPtr<PDF::Document> m_document; RefPtr<PDF::Document> m_document;
u32 m_current_page_index { 0 }; u32 m_current_page_index { 0 };
Vector<HashMap<u32, RefPtr<Gfx::Bitmap>>> m_rendered_page_list; Vector<HashMap<u32, RenderedPage>> m_rendered_page_list;
u8 m_zoom_level { initial_zoom_level }; u8 m_zoom_level { initial_zoom_level };
Gfx::IntPoint m_pan_starting_position; Gfx::IntPoint m_pan_starting_position;
int m_rotations { 0 };
}; };

View file

@ -130,13 +130,25 @@ void PDFViewerWidget::create_toolbar()
m_viewer->reset_zoom(); 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_in_action->set_enabled(false);
m_zoom_out_action->set_enabled(false); m_zoom_out_action->set_enabled(false);
m_reset_zoom_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_in_action);
toolbar.add_action(*m_zoom_out_action); toolbar.add_action(*m_zoom_out_action);
toolbar.add_action(*m_reset_zoom_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) 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_in_action->set_enabled(true);
m_zoom_out_action->set_enabled(true); m_zoom_out_action->set_enabled(true);
m_reset_zoom_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()) { if (document->outline()) {
auto outline = document->outline(); auto outline = document->outline();

View file

@ -38,6 +38,8 @@ private:
RefPtr<GUI::Action> m_zoom_in_action; RefPtr<GUI::Action> m_zoom_in_action;
RefPtr<GUI::Action> m_zoom_out_action; RefPtr<GUI::Action> m_zoom_out_action;
RefPtr<GUI::Action> m_reset_zoom_action; RefPtr<GUI::Action> m_reset_zoom_action;
RefPtr<GUI::Action> m_rotate_counterclockwise_action;
RefPtr<GUI::Action> m_rotate_clockwise_action;
bool m_sidebar_open { false }; bool m_sidebar_open { false };
ByteBuffer m_buffer; ByteBuffer m_buffer;