1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-22 17:25:07 +00:00

LibHTML: Make hit testing work for LayoutText

LayoutText can't simply rely on its LayoutNode::rect() for hit testing.
Instead, we have to iterate over the individual runs and see if we're
hitting any of them.

Also, LayoutNode::hit_test() now always recurses into children, since
we can't trust the rect() to tell the truth (inline rects are wrong.)
This commit is contained in:
Andreas Kling 2019-09-29 11:32:00 +02:00
parent aac8b091a4
commit 13860e4dd8
3 changed files with 46 additions and 12 deletions

View file

@ -222,6 +222,21 @@ void LayoutText::layout()
rect().set_bottom(last_run.pos.y() + m_font->glyph_height());
}
template<typename Callback>
void LayoutText::for_each_run(Callback callback) const
{
for (auto& run : m_runs) {
Rect rect {
run.pos.x(),
run.pos.y(),
m_font->width(run.text),
m_font->glyph_height()
};
if (callback(run, rect) == IterationDecision::Break)
break;
}
}
void LayoutText::render(RenderingContext& context)
{
auto& painter = context.painter();
@ -232,16 +247,23 @@ void LayoutText::render(RenderingContext& context)
bool is_underline = text_decoration == "underline";
for (auto& run : m_runs) {
Rect rect {
run.pos.x(),
run.pos.y(),
m_font->width(run.text),
m_font->glyph_height()
};
for_each_run([&](auto& run, auto& rect) {
painter.draw_text(rect, run.text, TextAlignment::TopLeft, color);
if (is_underline)
painter.draw_line(rect.bottom_left().translated(0, 1), rect.bottom_right().translated(0, 1), color);
}
return IterationDecision::Continue;
});
}
HitTestResult LayoutText::hit_test(const Point& position) const
{
HitTestResult result;
for_each_run([&](auto&, auto& rect) {
if (rect.contains(position)) {
result.layout_node = this;
return IterationDecision::Break;
}
return IterationDecision::Continue;
});
return result;
}