Skip to content

Commit 54d95fc

Browse files
gmtakalenikaliaksandr
authored andcommitted
LibWeb: Unify selection and cursor rects for painting
Instead of calculating the cursor rect separately, reuse PaintableFragment::range_rect() and check for the selection state of 'None' where appropriate.
1 parent aa1abe7 commit 54d95fc

File tree

3 files changed

+18
-35
lines changed

3 files changed

+18
-35
lines changed

Libraries/LibWeb/DOM/Range.cpp

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,7 +1163,10 @@ GC::Ref<Geometry::DOMRectList> Range::get_client_rects()
11631163
for (GC::Ptr<Node> node = start_node; node && node != end_node->next_in_pre_order(); node = node->next_in_pre_order()) {
11641164
auto selection_state = Painting::Paintable::SelectionState::Full;
11651165
if (node == start_node && node == end_node) {
1166-
selection_state = Painting::Paintable::SelectionState::StartAndEnd;
1166+
if (m_start_offset == m_end_offset)
1167+
selection_state = Painting::Paintable::SelectionState::None;
1168+
else
1169+
selection_state = Painting::Paintable::SelectionState::StartAndEnd;
11671170
} else if (node == start_node) {
11681171
selection_state = Painting::Paintable::SelectionState::Start;
11691172
} else if (node == end_node) {
@@ -1186,17 +1189,12 @@ GC::Ref<Geometry::DOMRectList> Range::get_client_rects()
11861189
// are identical), include scaled DOMRect object (for the part that is selected, not the whole line box).
11871190
auto const& text = static_cast<DOM::Text const&>(*node);
11881191
auto const* paintable = text.paintable();
1189-
if (paintable) {
1190-
auto const* containing_block = paintable->containing_block();
1191-
if (is<Painting::PaintableWithLines>(*containing_block)) {
1192-
auto const& paintable_lines = static_cast<Painting::PaintableWithLines const&>(*containing_block);
1193-
auto fragments = paintable_lines.fragments();
1192+
if (paintable && selection_state != Painting::Paintable::SelectionState::None) {
1193+
if (auto const* paintable_lines = as_if<Painting::PaintableWithLines>(paintable->containing_block())) {
1194+
auto fragments = paintable_lines->fragments();
11941195
for (auto frag = fragments.begin(); frag != fragments.end(); frag++) {
11951196
auto rect = frag->range_rect(selection_state, start_offset(), end_offset());
1196-
if (rect.is_empty())
1197-
continue;
1198-
rects.append(Geometry::DOMRect::create(realm(),
1199-
Gfx::FloatRect(rect)));
1197+
rects.append(Geometry::DOMRect::create(realm(), rect.to_type<float>()));
12001198
}
12011199
} else {
12021200
dbgln("FIXME: Failed to get client rects for node {}", node->debug_description());

Libraries/LibWeb/Painting/PaintableBox.cpp

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -742,22 +742,9 @@ void paint_cursor_if_needed(DisplayListRecordingContext& context, TextPaintable
742742
if (caret_color.alpha() == 0)
743743
return;
744744

745-
auto fragment_rect = fragment.absolute_rect();
746-
auto text = fragment.text();
745+
auto cursor_rect = fragment.range_rect(paintable.selection_state(), cursor_position->offset(), cursor_position->offset());
746+
VERIFY(cursor_rect.width() == 1);
747747

748-
auto const& font = fragment.glyph_run() ? fragment.glyph_run()->font() : fragment.layout_node().first_available_font();
749-
auto cursor_offset = font.width(text.substring_view(0, cursor_position->offset() - fragment.start_offset()));
750-
751-
auto font_metrics = font.pixel_metrics();
752-
753-
auto cursor_height = font_metrics.ascent + font_metrics.descent;
754-
755-
CSSPixelRect cursor_rect {
756-
fragment_rect.x() + CSSPixels::nearest_value_for(cursor_offset),
757-
fragment_rect.top() + fragment.baseline() - CSSPixels::nearest_value_for(font_metrics.ascent),
758-
1,
759-
CSSPixels::nearest_value_for(cursor_height)
760-
};
761748
auto cursor_device_rect = context.rounded_device_rect(cursor_rect).to_type<int>();
762749

763750
context.display_list_recorder().fill_rect(cursor_device_rect, caret_color);

Libraries/LibWeb/Painting/PaintableFragment.cpp

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,6 @@ size_t PaintableFragment::index_in_node_for_point(CSSPixelPoint position) const
6565

6666
CSSPixelRect PaintableFragment::range_rect(Paintable::SelectionState selection_state, size_t start_offset_in_code_units, size_t end_offset_in_code_units) const
6767
{
68-
if (selection_state == Paintable::SelectionState::None)
69-
return {};
70-
7168
if (selection_state == Paintable::SelectionState::Full)
7269
return absolute_rect();
7370

@@ -77,16 +74,13 @@ CSSPixelRect PaintableFragment::range_rect(Paintable::SelectionState selection_s
7774
auto const& font = glyph_run() ? glyph_run()->font() : layout_node().first_available_font();
7875
auto text = this->text();
7976

80-
if (selection_state == Paintable::SelectionState::StartAndEnd) {
77+
if (first_is_one_of(selection_state, Paintable::SelectionState::StartAndEnd, Paintable::SelectionState::None)) {
8178
// we are in the start/end node (both the same)
8279
if (start_index > end_offset_in_code_units)
8380
return {};
8481
if (end_index < start_offset_in_code_units)
8582
return {};
8683

87-
if (start_offset_in_code_units == end_offset_in_code_units)
88-
return {};
89-
9084
auto selection_start_in_this_fragment = max(0, start_offset_in_code_units - m_start_offset);
9185
auto selection_end_in_this_fragment = min(m_length_in_code_units, end_offset_in_code_units - m_start_offset);
9286
auto pixel_distance_to_first_selected_character = CSSPixels::nearest_value_for(font.width(text.substring_view(0, selection_start_in_this_fragment)));
@@ -180,7 +174,11 @@ Gfx::Orientation PaintableFragment::orientation() const
180174

181175
CSSPixelRect PaintableFragment::selection_rect() const
182176
{
183-
if (auto focused_area = paintable().document().focused_area(); is<HTML::FormAssociatedTextControlElement>(focused_area.ptr())) {
177+
auto const selection_state = paintable().selection_state();
178+
if (selection_state == Paintable::SelectionState::None)
179+
return {};
180+
181+
if (auto const* focused_area = as_if<HTML::FormAssociatedTextControlElement>(paintable().document().focused_area().ptr())) {
184182
HTML::FormAssociatedTextControlElement const* text_control_element = nullptr;
185183
if (auto const* input_element = as_if<HTML::HTMLInputElement>(*focused_area)) {
186184
text_control_element = input_element;
@@ -191,7 +189,7 @@ CSSPixelRect PaintableFragment::selection_rect() const
191189
}
192190
auto selection_start = text_control_element->selection_start();
193191
auto selection_end = text_control_element->selection_end();
194-
return range_rect(paintable().selection_state(), selection_start, selection_end);
192+
return range_rect(selection_state, selection_start, selection_end);
195193
}
196194

197195
auto selection = paintable().document().get_selection();
@@ -201,7 +199,7 @@ CSSPixelRect PaintableFragment::selection_rect() const
201199
if (!range)
202200
return {};
203201

204-
return range_rect(paintable().selection_state(), range->start_offset(), range->end_offset());
202+
return range_rect(selection_state, range->start_offset(), range->end_offset());
205203
}
206204

207205
Utf16View PaintableFragment::text() const

0 commit comments

Comments
 (0)