diff --git a/Libraries/LibWeb/PageView.cpp b/Libraries/LibWeb/PageView.cpp index 756a63eb01..ac82db9e8e 100644 --- a/Libraries/LibWeb/PageView.cpp +++ b/Libraries/LibWeb/PageView.cpp @@ -28,7 +28,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -45,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -60,12 +63,58 @@ PageView::PageView() { set_should_hide_unnecessary_scrollbars(true); set_background_role(ColorRole::Base); + + m_copy_action = GUI::CommonActions::make_copy_action([this](auto&) { + GUI::Clipboard::the().set_data(selected_text(), "text/plain"); + }); } PageView::~PageView() { } +String PageView::selected_text() const +{ + StringBuilder builder; + auto* layout_root = this->layout_root(); + if (!layout_root) + return {}; + if (!layout_root->selection().is_valid()) + return {}; + + auto selection = layout_root->selection().normalized(); + + if (selection.start().layout_node == selection.end().layout_node) { + if (!is(*selection.start().layout_node)) + return ""; + return to(*selection.start().layout_node).text_for_rendering().substring(selection.start().index_in_node, selection.end().index_in_node - selection.start().index_in_node + 1); + } + + // Start node + auto layout_node = selection.start().layout_node; + if (is(*layout_node)) { + auto& text = to(*layout_node).text_for_rendering(); + builder.append(text.substring(selection.start().index_in_node, text.length() - selection.start().index_in_node)); + } + + // Middle nodes + layout_node = layout_node->next_in_pre_order(); + while (layout_node && layout_node != selection.end().layout_node) { + if (is(*layout_node)) + builder.append(to(*layout_node).text_for_rendering()); + layout_node = layout_node->next_in_pre_order(); + } + + // End node + ASSERT(layout_node == selection.end().layout_node); + if (is(*layout_node)) { + auto& text = to(*layout_node).text_for_rendering(); + builder.append(text.substring(0, selection.end().index_in_node + 1)); + } + + return builder.to_string(); +} + void PageView::page_did_layout() { set_content_size(layout_root()->size().to_int_size()); diff --git a/Libraries/LibWeb/PageView.h b/Libraries/LibWeb/PageView.h index e1d8dce03a..e45900fa1a 100644 --- a/Libraries/LibWeb/PageView.h +++ b/Libraries/LibWeb/PageView.h @@ -73,6 +73,9 @@ public: virtual bool accepts_focus() const override { return true; } + GUI::Action& copy_action() { return *m_copy_action; } + String selected_text() const; + private: PageView(); @@ -114,6 +117,8 @@ private: bool m_should_show_line_box_borders { false }; NonnullOwnPtr m_page; + + RefPtr m_copy_action; }; }