LibWeb/Layout: Honor hanging and each-line in text-indent

This commit is contained in:
Sam Atkins 2025-11-18 12:47:17 +00:00 committed by Jelle Raaijmakers
parent c4b9e7eadf
commit fd4888e800
Notes: github-actions[bot] 2025-11-20 15:03:47 +00:00
4 changed files with 129 additions and 7 deletions

View file

@ -19,6 +19,8 @@ LineBuilder::LineBuilder(InlineFormattingContext& context, LayoutState& layout_s
{
auto text_indent = m_context.containing_block().computed_values().text_indent();
m_text_indent = text_indent.length_percentage.to_px(m_context.containing_block(), m_containing_block_used_values.content_width());
m_text_indent_each_line = text_indent.each_line;
m_text_indent_hanging = text_indent.hanging;
begin_new_line(false);
}
@ -37,7 +39,7 @@ void LineBuilder::break_line(ForcedBreak forced_break, Optional<CSSPixels> next_
bool floats_intrude_at_current_y = false;
do {
m_containing_block_used_values.line_boxes.append(LineBox(m_direction, m_writing_mode));
begin_new_line(true, break_count == 0);
begin_new_line(true, break_count == 0, forced_break);
break_count++;
floats_intrude_at_current_y = m_context.any_floats_intrude_at_block_offset(m_current_block_offset);
} while (floats_intrude_at_current_y
@ -45,7 +47,7 @@ void LineBuilder::break_line(ForcedBreak forced_break, Optional<CSSPixels> next_
|| (next_item_width.value_or(0) > m_available_width_for_current_line)));
}
void LineBuilder::begin_new_line(bool increment_y, bool is_first_break_in_sequence)
void LineBuilder::begin_new_line(bool increment_y, bool is_first_break_in_sequence, ForcedBreak forced_break)
{
if (increment_y) {
if (is_first_break_in_sequence) {
@ -66,13 +68,19 @@ void LineBuilder::begin_new_line(bool increment_y, bool is_first_break_in_sequen
}
}
recalculate_available_space();
ensure_last_line_box().m_original_available_width = m_available_width_for_current_line;
auto& line_box = ensure_last_line_box();
line_box.m_original_available_width = m_available_width_for_current_line;
m_max_height_on_current_line = 0;
m_last_line_needs_update = true;
// FIXME: Support text-indent with "each-line".
if (m_containing_block_used_values.line_boxes.size() <= 1)
ensure_last_line_box().m_inline_length += m_text_indent;
bool should_indent = m_containing_block_used_values.line_boxes.size() <= 1
|| (m_text_indent_each_line && forced_break == ForcedBreak::Yes);
if (m_text_indent_hanging)
should_indent = !should_indent;
if (should_indent)
line_box.m_inline_length += m_text_indent;
}
LineBox& LineBuilder::ensure_last_line_box()

View file

@ -48,7 +48,7 @@ public:
void did_introduce_clearance(CSSPixels);
private:
void begin_new_line(bool increment_y, bool is_first_break_in_sequence = true);
void begin_new_line(bool increment_y, bool is_first_break_in_sequence = true, ForcedBreak = ForcedBreak::No);
bool should_break(CSSPixels next_item_width);
@ -61,6 +61,8 @@ private:
CSSPixels m_current_block_offset { 0 };
CSSPixels m_max_height_on_current_line { 0 };
CSSPixels m_text_indent { 0 };
bool m_text_indent_hanging : 1 { false };
bool m_text_indent_each_line : 1 { false };
CSS::Direction m_direction { CSS::Direction::Ltr };
CSS::WritingMode m_writing_mode { CSS::WritingMode::HorizontalTb };

View file

@ -0,0 +1,48 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>text-indent 'each-line' and 'hanging' modifiers</title>
<link rel="stylesheet" href="../../../../../../data/fonts/ahem.css" />
<style>
div { width:80px; font: 10px Ahem; background-color:lightgray; }
.indent { color: blue; padding-left:4em; }
</style>
</head>
<body>
All black boxes should be left-aligned. All blue boxes should be right-aligned.
<div>
<span class="indent">xxxx</span><br>xxxx<br>xxxx
</div>
<br>
<div>
<span class="indent">xxxx</span> xxxx xxxx
</div>
<br>
<div>
<span class="indent">xxxx</span><br><span class="indent">xxxx</span><br><span class="indent">xxxx</span>
</div>
<br>
<div>
<span class="indent">xxxx</span> xxxx<br><span class="indent">xxxx</span>
</div>
<br>
<div>
xxxx<br><span class="indent">xxxx</span><br><span class="indent">xxxx</span>
</div>
<br>
<div>
xxxx <span class="indent">xxxx</span> <span class="indent">xxxx</span>
</div>
<br>
<div>
xxxx<br>xxxx<br>xxxx
</div>
<br>
<div>
xxxx <span class="indent">xxxx</span><br>xxxx
</div>
</body>
</html>

View file

@ -0,0 +1,64 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>text-indent 'each-line' and 'hanging' modifiers</title>
<link rel="author" title="Jaehun Lim" href="mailto:ljaehun.lim@samsung.com">
<link rel="help" href="https://drafts.csswg.org/css-text-3/#text-indent-property">
<link rel="match" href="../../../../../expected/wpt-import/css/css-text/text-indent/reference/text-indent-each-line-hanging-ref.html">
<meta name="assert" content="'each-line' and 'hanging' properly works">
<link rel="stylesheet" href="../../../../../data/fonts/ahem.css" />
<style>
div { width:80px; font: 10px Ahem; background-color:lightgray; }
.normal { text-indent: 4em; }
.eachline { text-indent: 4em each-line; }
.hanging { text-indent: 4em hanging; }
.eachlinehanging { text-indent: 4em each-line hanging; }
.indent { color: blue; }
</style>
</head>
<body>
All black boxes should be left-aligned. All blue boxes should be right-aligned.
<!-- normal text-indent -->
<div class="normal">
<span class="indent">xxxx</span> xxxx<br>xxxx
</div>
<br>
<!-- each-line with a soft wrap break -->
<div class="eachline">
<span class="indent">xxxx</span> xxxx xxxx
</div>
<br>
<!-- each-line with a forced line break -->
<div class="eachline">
<span class="indent">xxxx</span><br><span class="indent">xxxx</span><br><span class="indent">xxxx</span>
</div>
<br>
<!-- each-line with a soft wrap break and a forced line break -->
<div class="eachline">
<span class="indent">xxxx</span> xxxx<br><span class="indent">xxxx</span>
</div>
<br>
<!-- normal text-indent with hanging -->
<div class="hanging">
xxxx <span class="indent">xxxx</span><br><span class="indent">xxxx</span>
</div>
<br>
<!-- each-line and hanging with a soft wrap break -->
<div class="eachlinehanging">
xxxx <span class="indent">xxxx</span> <span class="indent">xxxx</span>
</div>
<br>
<!-- each-line and hanging with a forced line break -->
<div class="eachlinehanging">
xxxx<br>xxxx<br>xxxx
</div>
<br>
<!-- each-line and hanging with a soft wrap break and a forced line break -->
<div class="eachlinehanging">
xxxx <span class="indent">xxxx</span><br>xxxx
</div>
</body>
</html>