mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 09:00: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: https://github.com/LadybirdBrowser/ladybird/commit/9395b266c6a 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.paintable().hit_test(position, type, callback) == 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)
|
||||
return TraversalDecision::Break;
|
||||
} else if (type == HitTestType::TextCursor) {
|
||||
|
|
|
@ -36,13 +36,23 @@ CSSPixelRect const PaintableFragment::absolute_rect() const
|
|||
return rect;
|
||||
}
|
||||
|
||||
int PaintableFragment::text_index_at(CSSPixels x) const
|
||||
int PaintableFragment::text_index_at(CSSPixelPoint position) const
|
||||
{
|
||||
if (!is<TextPaintable>(paintable()))
|
||||
return 0;
|
||||
|
||||
CSSPixels relative_x = x - absolute_rect().x();
|
||||
if (relative_x < 0)
|
||||
CSSPixels relative_inline_offset = [&]() {
|
||||
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;
|
||||
|
||||
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());
|
||||
if (i + 1 < glyphs.size()) {
|
||||
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;
|
||||
} else {
|
||||
if (relative_x >= glyph_position)
|
||||
if (relative_inline_offset >= glyph_position)
|
||||
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 rect = absolute_rect();
|
||||
switch (orientation()) {
|
||||
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;
|
||||
}
|
||||
|
@ -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 rect = absolute_rect();
|
||||
switch (orientation()) {
|
||||
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;
|
||||
}
|
||||
|
@ -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 rect = absolute_rect();
|
||||
switch (orientation()) {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ public:
|
|||
CSSPixels width() const { return m_size.width(); }
|
||||
CSSPixels height() const { return m_size.height(); }
|
||||
|
||||
int text_index_at(CSSPixels) const;
|
||||
int text_index_at(CSSPixelPoint) const;
|
||||
|
||||
StringView string_view() const;
|
||||
|
||||
|
|
Loading…
Reference in a new issue