summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Libraries/LibWeb/InProcessWebView.cpp1
-rw-r--r--Libraries/LibWeb/Layout/LayoutDocument.cpp26
-rw-r--r--Libraries/LibWeb/Layout/LayoutDocument.h2
-rw-r--r--Libraries/LibWeb/Layout/LayoutNode.h20
-rw-r--r--Libraries/LibWeb/Layout/LineBoxFragment.cpp24
-rw-r--r--Libraries/LibWeb/Page/EventHandler.cpp2
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();