Parcourir la source

Ladybird: Add screenshot actions to the page context menu

Browser on Serenity has these actions already.
Timothy Flynn il y a 2 ans
Parent
commit
b0edc7b6e4
4 fichiers modifiés avec 74 ajouts et 0 suppressions
  1. 53 0
      Ladybird/Tab.cpp
  2. 6 0
      Ladybird/Tab.h
  3. 12 0
      Ladybird/WebContentView.cpp
  4. 3 0
      Ladybird/WebContentView.h

+ 53 - 0
Ladybird/Tab.cpp

@@ -9,8 +9,12 @@
 #include "BrowserWindow.h"
 #include "BrowserWindow.h"
 #include "Settings.h"
 #include "Settings.h"
 #include "Utilities.h"
 #include "Utilities.h"
+#include <AK/LexicalPath.h>
 #include <Browser/History.h>
 #include <Browser/History.h>
+#include <LibCore/DateTime.h>
+#include <LibCore/StandardPaths.h>
 #include <LibGfx/ImageFormats/BMPWriter.h>
 #include <LibGfx/ImageFormats/BMPWriter.h>
+#include <LibGfx/ImageFormats/PNGWriter.h>
 #include <QClipboard>
 #include <QClipboard>
 #include <QCoreApplication>
 #include <QCoreApplication>
 #include <QFont>
 #include <QFont>
@@ -18,6 +22,7 @@
 #include <QGuiApplication>
 #include <QGuiApplication>
 #include <QImage>
 #include <QImage>
 #include <QMenu>
 #include <QMenu>
+#include <QMessageBox>
 #include <QPainter>
 #include <QPainter>
 #include <QPlainTextEdit>
 #include <QPlainTextEdit>
 #include <QPoint>
 #include <QPoint>
@@ -183,6 +188,24 @@ Tab::Tab(BrowserWindow* window, StringView webdriver_content_ipc_path, WebView::
         return Gfx::IntRect { m_window->x(), m_window->y(), m_window->width(), m_window->height() };
         return Gfx::IntRect { m_window->x(), m_window->y(), m_window->width(), m_window->height() };
     });
     });
 
 
+    auto* take_visible_screenshot_action = new QAction("Take &Visible Screenshot", this);
+    take_visible_screenshot_action->setIcon(QIcon(QString("%1/res/icons/16x16/filetype-image.png").arg(s_serenity_resource_root.characters())));
+    QObject::connect(take_visible_screenshot_action, &QAction::triggered, this, [this]() {
+        if (auto result = take_screenshot(ScreenshotType::Visible); result.is_error()) {
+            auto error = String::formatted("{}", result.error()).release_value_but_fixme_should_propagate_errors();
+            QMessageBox::warning(this, "Ladybird", qstring_from_ak_string(error));
+        }
+    });
+
+    auto* take_full_screenshot_action = new QAction("Take &Full Screenshot", this);
+    take_full_screenshot_action->setIcon(QIcon(QString("%1/res/icons/16x16/filetype-image.png").arg(s_serenity_resource_root.characters())));
+    QObject::connect(take_full_screenshot_action, &QAction::triggered, this, [this]() {
+        if (auto result = take_screenshot(ScreenshotType::Full); result.is_error()) {
+            auto error = String::formatted("{}", result.error()).release_value_but_fixme_should_propagate_errors();
+            QMessageBox::warning(this, "Ladybird", qstring_from_ak_string(error));
+        }
+    });
+
     m_page_context_menu = make<QMenu>("Context menu", this);
     m_page_context_menu = make<QMenu>("Context menu", this);
     m_page_context_menu->addAction(&m_window->go_back_action());
     m_page_context_menu->addAction(&m_window->go_back_action());
     m_page_context_menu->addAction(&m_window->go_forward_action());
     m_page_context_menu->addAction(&m_window->go_forward_action());
@@ -191,6 +214,9 @@ Tab::Tab(BrowserWindow* window, StringView webdriver_content_ipc_path, WebView::
     m_page_context_menu->addAction(&m_window->copy_selection_action());
     m_page_context_menu->addAction(&m_window->copy_selection_action());
     m_page_context_menu->addAction(&m_window->select_all_action());
     m_page_context_menu->addAction(&m_window->select_all_action());
     m_page_context_menu->addSeparator();
     m_page_context_menu->addSeparator();
+    m_page_context_menu->addAction(take_visible_screenshot_action);
+    m_page_context_menu->addAction(take_full_screenshot_action);
+    m_page_context_menu->addSeparator();
     m_page_context_menu->addAction(&m_window->view_source_action());
     m_page_context_menu->addAction(&m_window->view_source_action());
     m_page_context_menu->addAction(&m_window->inspect_dom_node_action());
     m_page_context_menu->addAction(&m_window->inspect_dom_node_action());
 
 
@@ -424,6 +450,33 @@ void Tab::copy_link_url(URL const& url)
     clipboard->setText(qstring_from_ak_deprecated_string(url.to_deprecated_string()));
     clipboard->setText(qstring_from_ak_deprecated_string(url.to_deprecated_string()));
 }
 }
 
 
+ErrorOr<void> Tab::take_screenshot(ScreenshotType type)
+{
+    Gfx::ShareableBitmap bitmap;
+
+    switch (type) {
+    case ScreenshotType::Visible:
+        bitmap = view().take_screenshot();
+        break;
+    case ScreenshotType::Full:
+        bitmap = view().take_document_screenshot();
+        break;
+    }
+
+    if (!bitmap.is_valid())
+        return Error::from_string_view("Failed to take a screenshot of the current tab"sv);
+
+    LexicalPath path { Core::StandardPaths::downloads_directory() };
+    path = path.append(TRY(Core::DateTime::now().to_string("screenshot-%Y-%m-%d-%H-%M-%S.png"sv)));
+
+    auto encoded = TRY(Gfx::PNGWriter::encode(*bitmap.bitmap()));
+
+    auto screenshot_file = TRY(Core::File::open(path.string(), Core::File::OpenMode::Write));
+    TRY(screenshot_file->write_until_depleted(encoded));
+
+    return {};
+}
+
 void Tab::location_edit_return_pressed()
 void Tab::location_edit_return_pressed()
 {
 {
     navigate(m_location_edit->text());
     navigate(m_location_edit->text());

+ 6 - 0
Ladybird/Tab.h

@@ -60,6 +60,12 @@ private:
     void open_link_in_new_tab(URL const&);
     void open_link_in_new_tab(URL const&);
     void copy_link_url(URL const&);
     void copy_link_url(URL const&);
 
 
+    enum class ScreenshotType {
+        Visible,
+        Full,
+    };
+    ErrorOr<void> take_screenshot(ScreenshotType);
+
     QBoxLayout* m_layout;
     QBoxLayout* m_layout;
     QToolBar* m_toolbar { nullptr };
     QToolBar* m_toolbar { nullptr };
     QToolButton* m_reset_zoom_button { nullptr };
     QToolButton* m_reset_zoom_button { nullptr };

+ 12 - 0
Ladybird/WebContentView.cpp

@@ -637,6 +637,18 @@ void WebContentView::create_client(WebView::EnableCallgrindProfiling enable_call
         client().async_connect_to_webdriver(m_webdriver_content_ipc_path);
         client().async_connect_to_webdriver(m_webdriver_content_ipc_path);
 }
 }
 
 
+Gfx::ShareableBitmap WebContentView::take_screenshot() const
+{
+    if (auto* bitmap = m_client_state.has_usable_bitmap ? m_client_state.front_bitmap.bitmap.ptr() : m_backup_bitmap.ptr())
+        return bitmap->to_shareable_bitmap();
+    return {};
+}
+
+Gfx::ShareableBitmap WebContentView::take_document_screenshot()
+{
+    return client().take_document_screenshot();
+}
+
 void WebContentView::handle_web_content_process_crash()
 void WebContentView::handle_web_content_process_crash()
 {
 {
     dbgln("WebContent process crashed!");
     dbgln("WebContent process crashed!");

+ 3 - 0
Ladybird/WebContentView.h

@@ -113,6 +113,9 @@ public:
     Gfx::IntPoint to_content(Gfx::IntPoint) const;
     Gfx::IntPoint to_content(Gfx::IntPoint) const;
     Gfx::IntPoint to_widget(Gfx::IntPoint) const;
     Gfx::IntPoint to_widget(Gfx::IntPoint) const;
 
 
+    Gfx::ShareableBitmap take_screenshot() const;
+    Gfx::ShareableBitmap take_document_screenshot();
+
     enum class PaletteMode {
     enum class PaletteMode {
         Default,
         Default,
         Dark,
         Dark,