diff options
-rw-r--r-- | Libraries/LibWeb/InProcessWebView.cpp | 1 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutDocument.cpp | 26 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutDocument.h | 2 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutNode.h | 20 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LineBoxFragment.cpp | 24 | ||||
-rw-r--r-- | Libraries/LibWeb/Page/EventHandler.cpp | 2 |
6 files changed, 60 insertions, 15 deletions
diff --git a/Libraries/LibWeb/InProcessWebView.cpp b/Libraries/LibWeb/InProcessWebView.cpp index 4b9a9f87b0..96f2fa2c4e 100644 --- a/Libraries/LibWeb/InProcessWebView.cpp +++ b/Libraries/LibWeb/InProcessWebView.cpp @@ -110,6 +110,7 @@ void InProcessWebView::select_all() last_layout_node_index_in_node = downcast<LayoutText>(*last_layout_node).text_for_rendering().length() - 1; layout_root->selection().set({ first_layout_node, 0 }, { last_layout_node, last_layout_node_index_in_node }); + layout_root->recompute_selection_states(); update(); } diff --git a/Libraries/LibWeb/Layout/LayoutDocument.cpp b/Libraries/LibWeb/Layout/LayoutDocument.cpp index 541ff7ddd7..b891874887 100644 --- a/Libraries/LibWeb/Layout/LayoutDocument.cpp +++ b/Libraries/LibWeb/Layout/LayoutDocument.cpp @@ -120,4 +120,30 @@ HitTestResult LayoutDocument::hit_test(const Gfx::IntPoint& position, HitTestTyp return stacking_context()->hit_test(position, type); } +void LayoutDocument::recompute_selection_states() +{ + SelectionState state = SelectionState::None; + + auto selection = this->selection().normalized(); + + for_each_in_subtree([&](auto& layout_node) { + if (!selection.is_valid()) { + // Everything gets SelectionState::None. + } else if (&layout_node == selection.start().layout_node && &layout_node == selection.end().layout_node) { + state = SelectionState::StartAndEnd; + } else if (&layout_node == selection.start().layout_node) { + state = SelectionState::Start; + } else if (&layout_node == selection.end().layout_node) { + state = SelectionState::End; + } else { + if (state == SelectionState::Start) + state = SelectionState::Full; + else if (state == SelectionState::End || state == SelectionState::StartAndEnd) + state = SelectionState::None; + } + layout_node.set_selection_state(state); + return IterationDecision::Continue; + }); +} + } diff --git a/Libraries/LibWeb/Layout/LayoutDocument.h b/Libraries/LibWeb/Layout/LayoutDocument.h index 79dbd7312a..2f18e90f44 100644 --- a/Libraries/LibWeb/Layout/LayoutDocument.h +++ b/Libraries/LibWeb/Layout/LayoutDocument.h @@ -54,6 +54,8 @@ public: void build_stacking_context_tree(); + void recompute_selection_states(); + private: LayoutRange m_selection; }; diff --git a/Libraries/LibWeb/Layout/LayoutNode.h b/Libraries/LibWeb/Layout/LayoutNode.h index b441c3afe2..246d40761f 100644 --- a/Libraries/LibWeb/Layout/LayoutNode.h +++ b/Libraries/LibWeb/Layout/LayoutNode.h @@ -43,6 +43,14 @@ namespace Web { struct HitTestResult { RefPtr<LayoutNode> layout_node; int index_in_node { 0 }; + + enum InternalPosition { + None, + Before, + Inside, + After, + }; + InternalPosition internal_position { None }; }; enum class HitTestType { @@ -142,6 +150,17 @@ public: float font_size() const; + enum class SelectionState { + None, // No selection + Start, // Selection starts in this LayoutNode + End, // Selection ends in this LayoutNode + StartAndEnd, // Selection starts and ends in this LayoutNode + Full, // Selection starts before and ends after this LayoutNode + }; + + SelectionState selection_state() const { return m_selection_state; } + void set_selection_state(SelectionState state) { m_selection_state = state; } + protected: LayoutNode(DOM::Document&, DOM::Node*); @@ -155,6 +174,7 @@ private: bool m_has_style { false }; bool m_visible { true }; bool m_children_are_inline { false }; + SelectionState m_selection_state { SelectionState::None }; }; class LayoutNodeWithStyle : public LayoutNode { diff --git a/Libraries/LibWeb/Layout/LineBoxFragment.cpp b/Libraries/LibWeb/Layout/LineBoxFragment.cpp index 719ee8a5cd..af95972d18 100644 --- a/Libraries/LibWeb/Layout/LineBoxFragment.cpp +++ b/Libraries/LibWeb/Layout/LineBoxFragment.cpp @@ -100,6 +100,12 @@ int LineBoxFragment::text_index_at(float x) const Gfx::FloatRect LineBoxFragment::selection_rect(const Gfx::Font& font) const { + if (layout_node().selection_state() == LayoutNode::SelectionState::None) + return {}; + + if (layout_node().selection_state() == LayoutNode::SelectionState::Full) + return absolute_rect(); + auto selection = layout_node().root().selection().normalized(); if (!selection.is_valid()) return {}; @@ -110,7 +116,7 @@ Gfx::FloatRect LineBoxFragment::selection_rect(const Gfx::Font& font) const const auto end_index = m_start + m_length; auto text = this->text(); - if (&layout_node() == selection.start().layout_node && &layout_node() == selection.end().layout_node) { + if (layout_node().selection_state() == LayoutNode::SelectionState::StartAndEnd) { // we are in the start/end node (both the same) if (start_index > selection.end().index_in_node) return {}; @@ -128,7 +134,7 @@ Gfx::FloatRect LineBoxFragment::selection_rect(const Gfx::Font& font) const return rect; } - if (&layout_node() == selection.start().layout_node) { + if (layout_node().selection_state() == LayoutNode::SelectionState::Start) { // we are in the start node if (end_index < selection.start().index_in_node) return {}; @@ -144,7 +150,7 @@ Gfx::FloatRect LineBoxFragment::selection_rect(const Gfx::Font& font) const return rect; } - if (&layout_node() == selection.end().layout_node) { + if (layout_node().selection_state() == LayoutNode::SelectionState::End) { // we are in the end node if (start_index > selection.end().index_in_node) return {}; @@ -160,18 +166,6 @@ Gfx::FloatRect LineBoxFragment::selection_rect(const Gfx::Font& font) const return rect; } - - // are we in between start and end? - auto* node = selection.start().layout_node.ptr(); - bool is_fully_selected = false; - for (; node && node != selection.end().layout_node.ptr(); node = node->next_in_pre_order()) { - if (node == &layout_node()) { - is_fully_selected = true; - break; - } - } - if (is_fully_selected) - return absolute_rect(); return {}; } diff --git a/Libraries/LibWeb/Page/EventHandler.cpp b/Libraries/LibWeb/Page/EventHandler.cpp index 38a8bfb8cb..cba26e89ba 100644 --- a/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Libraries/LibWeb/Page/EventHandler.cpp @@ -157,6 +157,7 @@ bool EventHandler::handle_mousedown(const Gfx::IntPoint& position, unsigned butt if (result.layout_node && result.layout_node->node()) { m_frame.set_cursor_position(DOM::Position(*node, result.index_in_node)); layout_root()->selection().set({ result.layout_node, result.index_in_node }, {}); + layout_root()->recompute_selection_states(); dump_selection("MouseDown"); m_in_mouse_selection = true; } @@ -209,6 +210,7 @@ bool EventHandler::handle_mousemove(const Gfx::IntPoint& position, unsigned butt auto hit = layout_root()->hit_test(position, HitTestType::TextCursor); if (hit.layout_node && hit.layout_node->node()) { layout_root()->selection().set_end({ hit.layout_node, hit.index_in_node }); + layout_root()->recompute_selection_states(); } dump_selection("MouseMove"); page_client.page_did_change_selection(); |