LibWeb: Handle text-overflow: ellipsis with trailing whitespace

We should calculate whether we need to truncate text with an ellipsis
exclusive of any trailing collapsible whitespace.

This was causing issues where an inline element was automatically sized
(e.g. min-content) as we would calculate available width exclusive of
trailing collapsible whitespace and then our text chunk would be wider,
always inserting an ellipsis.

Fixes the visual element of #4048 but we still are incorrect in how we
collapse whitespace more generally
This commit is contained in:
Callum Law 2025-08-11 03:08:18 +12:00 committed by Sam Atkins
commit 027c9f53be
Notes: github-actions[bot] 2025-08-18 10:01:43 +00:00
3 changed files with 36 additions and 2 deletions

View file

@ -350,8 +350,28 @@ void InlineFormattingContext::generate_line_boxes()
&& text_node.computed_values().overflow_x() != CSS::Overflow::Visible) {
// We may need to do an ellipsis if the text is too long for the container
constexpr u32 ellipsis_codepoint = 0x2026;
if (m_available_space.has_value()
&& item.width.to_double() > m_available_space.value().width.to_px_or_zero().to_double()) {
// NOTE: We compute whether we need to truncate the text with an ellipsis based on the width of the
// text node EXCLUSIVE of trailing collapsible whitespace, this is because that trailing
// collapsible whitespace is removed later when we trim the line-boxes anyway.
// Note that this relies on the assumption that this text node is the last in this linebox (as
// there is only one text-node per line box when we have text-wrap: nowrap)
double width_without_trailing_collapsible_whitespace = item.width.to_double();
if (first_is_one_of(text_node.computed_values().white_space_collapse(), CSS::WhiteSpaceCollapse::Collapse, CSS::WhiteSpaceCollapse::PreserveBreaks)) {
auto last_text = text_node.text_for_rendering();
size_t last_fragment_length = last_text.length_in_code_units();
while (last_fragment_length) {
auto last_character = last_text.code_unit_at(--last_fragment_length);
if (!is_ascii_space(last_character))
break;
width_without_trailing_collapsible_whitespace -= item.glyph_run->font().glyph_width(last_character);
}
}
if (m_available_space.has_value() && width_without_trailing_collapsible_whitespace > m_available_space.value().width.to_px_or_zero().to_double()) {
// Do the ellipsis
auto& glyph_run = item.glyph_run;

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<span>abc</span>

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<link rel="match" href="../expected/text-overflow-ellipsis-with-trailing-whitespace-ref.html" />
<style>
#foo {
display: inline-block;
width: min-content;
overflow: hidden;
text-overflow: ellipsis;
text-wrap: nowrap;
}
</style>
<span id="foo">abc </span>