mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-18 07:22:22 +00:00
LibWeb: Support vertical text hit detection and selection
If a PaintableFragment has a vertical orientation, use y instead of x to compute the offset of each character in the text fragment.
This commit is contained in:
parent
02276360e9
commit
9395b266c6
Notes:
github-actions[bot]
2024-11-03 16:02:50 +00:00
Author: https://github.com/BenJilks
Commit: 9395b266c6
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2135
Reviewed-by: https://github.com/kalenikaliaksandr ✅
3 changed files with 53 additions and 13 deletions
|
@ -939,7 +939,7 @@ TraversalDecision PaintableWithLines::hit_test(CSSPixelPoint position, HitTestTy
|
||||||
if (fragment_absolute_rect.contains(position_adjusted_by_scroll_offset)) {
|
if (fragment_absolute_rect.contains(position_adjusted_by_scroll_offset)) {
|
||||||
if (fragment.paintable().hit_test(position, type, callback) == TraversalDecision::Break)
|
if (fragment.paintable().hit_test(position, type, callback) == TraversalDecision::Break)
|
||||||
return TraversalDecision::Break;
|
return TraversalDecision::Break;
|
||||||
HitTestResult hit_test_result { const_cast<Paintable&>(fragment.paintable()), fragment.text_index_at(position_adjusted_by_scroll_offset.x()), 0, 0 };
|
HitTestResult hit_test_result { const_cast<Paintable&>(fragment.paintable()), fragment.text_index_at(position_adjusted_by_scroll_offset), 0, 0 };
|
||||||
if (callback(hit_test_result) == TraversalDecision::Break)
|
if (callback(hit_test_result) == TraversalDecision::Break)
|
||||||
return TraversalDecision::Break;
|
return TraversalDecision::Break;
|
||||||
} else if (type == HitTestType::TextCursor) {
|
} else if (type == HitTestType::TextCursor) {
|
||||||
|
|
|
@ -36,13 +36,23 @@ CSSPixelRect const PaintableFragment::absolute_rect() const
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PaintableFragment::text_index_at(CSSPixels x) const
|
int PaintableFragment::text_index_at(CSSPixelPoint position) const
|
||||||
{
|
{
|
||||||
if (!is<TextPaintable>(paintable()))
|
if (!is<TextPaintable>(paintable()))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
CSSPixels relative_x = x - absolute_rect().x();
|
CSSPixels relative_inline_offset = [&]() {
|
||||||
if (relative_x < 0)
|
switch (orientation()) {
|
||||||
|
case Gfx::Orientation::Horizontal:
|
||||||
|
return position.x() - absolute_rect().x();
|
||||||
|
case Gfx::Orientation::Vertical:
|
||||||
|
return position.y() - absolute_rect().y();
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
if (relative_inline_offset < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
auto const& glyphs = m_glyph_run->glyphs();
|
auto const& glyphs = m_glyph_run->glyphs();
|
||||||
|
@ -50,10 +60,10 @@ int PaintableFragment::text_index_at(CSSPixels x) const
|
||||||
auto glyph_position = CSSPixels::nearest_value_for(glyphs[i].position.x());
|
auto glyph_position = CSSPixels::nearest_value_for(glyphs[i].position.x());
|
||||||
if (i + 1 < glyphs.size()) {
|
if (i + 1 < glyphs.size()) {
|
||||||
auto next_glyph_position = CSSPixels::nearest_value_for(glyphs[i + 1].position.x());
|
auto next_glyph_position = CSSPixels::nearest_value_for(glyphs[i + 1].position.x());
|
||||||
if (relative_x >= glyph_position && relative_x < next_glyph_position)
|
if (relative_inline_offset >= glyph_position && relative_inline_offset < next_glyph_position)
|
||||||
return m_start + i;
|
return m_start + i;
|
||||||
} else {
|
} else {
|
||||||
if (relative_x >= glyph_position)
|
if (relative_inline_offset >= glyph_position)
|
||||||
return m_start + i;
|
return m_start + i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,8 +100,18 @@ CSSPixelRect PaintableFragment::range_rect(Gfx::Font const& font, size_t start_o
|
||||||
auto pixel_width_of_selection = CSSPixels::nearest_value_for(font.width(text.substring_view(selection_start_in_this_fragment, selection_end_in_this_fragment - selection_start_in_this_fragment))) + 1;
|
auto pixel_width_of_selection = CSSPixels::nearest_value_for(font.width(text.substring_view(selection_start_in_this_fragment, selection_end_in_this_fragment - selection_start_in_this_fragment))) + 1;
|
||||||
|
|
||||||
auto rect = absolute_rect();
|
auto rect = absolute_rect();
|
||||||
rect.set_x(rect.x() + pixel_distance_to_first_selected_character);
|
switch (orientation()) {
|
||||||
rect.set_width(pixel_width_of_selection);
|
case Gfx::Orientation::Horizontal:
|
||||||
|
rect.set_x(rect.x() + pixel_distance_to_first_selected_character);
|
||||||
|
rect.set_width(pixel_width_of_selection);
|
||||||
|
break;
|
||||||
|
case Gfx::Orientation::Vertical:
|
||||||
|
rect.set_y(rect.y() + pixel_distance_to_first_selected_character);
|
||||||
|
rect.set_height(pixel_width_of_selection);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
@ -106,8 +126,18 @@ CSSPixelRect PaintableFragment::range_rect(Gfx::Font const& font, size_t start_o
|
||||||
auto pixel_width_of_selection = CSSPixels::nearest_value_for(font.width(text.substring_view(selection_start_in_this_fragment, selection_end_in_this_fragment - selection_start_in_this_fragment))) + 1;
|
auto pixel_width_of_selection = CSSPixels::nearest_value_for(font.width(text.substring_view(selection_start_in_this_fragment, selection_end_in_this_fragment - selection_start_in_this_fragment))) + 1;
|
||||||
|
|
||||||
auto rect = absolute_rect();
|
auto rect = absolute_rect();
|
||||||
rect.set_x(rect.x() + pixel_distance_to_first_selected_character);
|
switch (orientation()) {
|
||||||
rect.set_width(pixel_width_of_selection);
|
case Gfx::Orientation::Horizontal:
|
||||||
|
rect.set_x(rect.x() + pixel_distance_to_first_selected_character);
|
||||||
|
rect.set_width(pixel_width_of_selection);
|
||||||
|
break;
|
||||||
|
case Gfx::Orientation::Vertical:
|
||||||
|
rect.set_y(rect.y() + pixel_distance_to_first_selected_character);
|
||||||
|
rect.set_height(pixel_width_of_selection);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
@ -122,8 +152,18 @@ CSSPixelRect PaintableFragment::range_rect(Gfx::Font const& font, size_t start_o
|
||||||
auto pixel_width_of_selection = CSSPixels::nearest_value_for(font.width(text.substring_view(selection_start_in_this_fragment, selection_end_in_this_fragment - selection_start_in_this_fragment))) + 1;
|
auto pixel_width_of_selection = CSSPixels::nearest_value_for(font.width(text.substring_view(selection_start_in_this_fragment, selection_end_in_this_fragment - selection_start_in_this_fragment))) + 1;
|
||||||
|
|
||||||
auto rect = absolute_rect();
|
auto rect = absolute_rect();
|
||||||
rect.set_x(rect.x() + pixel_distance_to_first_selected_character);
|
switch (orientation()) {
|
||||||
rect.set_width(pixel_width_of_selection);
|
case Gfx::Orientation::Horizontal:
|
||||||
|
rect.set_x(rect.x() + pixel_distance_to_first_selected_character);
|
||||||
|
rect.set_width(pixel_width_of_selection);
|
||||||
|
break;
|
||||||
|
case Gfx::Orientation::Vertical:
|
||||||
|
rect.set_y(rect.y() + pixel_distance_to_first_selected_character);
|
||||||
|
rect.set_height(pixel_width_of_selection);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ public:
|
||||||
CSSPixels width() const { return m_size.width(); }
|
CSSPixels width() const { return m_size.width(); }
|
||||||
CSSPixels height() const { return m_size.height(); }
|
CSSPixels height() const { return m_size.height(); }
|
||||||
|
|
||||||
int text_index_at(CSSPixels) const;
|
int text_index_at(CSSPixelPoint) const;
|
||||||
|
|
||||||
StringView string_view() const;
|
StringView string_view() const;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue