LibWeb: Implement text-align: match-parent

At computed-value time, this is converted to whatever the parent's
computed value is. So it behaves a little like `inherit`, except that
an inherited start/end value uses the parent's start/end, which might
be different from the child's.
This commit is contained in:
Sam Atkins 2025-02-03 16:06:07 +00:00
parent 4f855286d7
commit 070c4a2045
Notes: github-actions[bot] 2025-02-05 17:46:38 +00:00
8 changed files with 154 additions and 3 deletions

View file

@ -523,6 +523,7 @@
"end",
"left",
"right",
"match-parent",
"-libweb-center",
"-libweb-left",
"-libweb-right"

View file

@ -234,7 +234,7 @@
"jis04",
"jis78",
"jis83",
"jis90",
"jis90",
"jump-both",
"jump-end",
"jump-none",
@ -267,6 +267,7 @@
"luminosity",
"mark",
"marktext",
"match-parent",
"math",
"math-auto",
"max-content",
@ -289,7 +290,7 @@
"nearest",
"nesw-resize",
"no-close-quote",
"no-common-ligatures",
"no-common-ligatures",
"no-contextual",
"no-discretionary-ligatures",
"no-drop",

View file

@ -2213,6 +2213,50 @@ void StyleComputer::resolve_effective_overflow_values(ComputedProperties& style)
}
}
static void compute_text_align(ComputedProperties& style, DOM::Element const& element, Optional<Selector::PseudoElement::Type> pseudo_element)
{
// https://drafts.csswg.org/css-text-4/#valdef-text-align-match-parent
// This value behaves the same as inherit (computes to its parents computed value) except that an inherited
// value of start or end is interpreted against the parents direction value and results in a computed value of
// either left or right. Computes to start when specified on the root element.
if (style.property(PropertyID::TextAlign).to_keyword() == Keyword::MatchParent) {
// If it's a pseudo-element, then the "parent" is the originating element instead.
auto const* parent = [&]() -> DOM::Element const* {
if (pseudo_element.has_value())
return &element;
return element.parent_element();
}();
if (parent) {
auto const& parent_text_align = parent->computed_properties()->property(PropertyID::TextAlign);
auto const& parent_direction = parent->computed_properties()->direction().value_or(Direction::Ltr);
switch (parent_text_align.to_keyword()) {
case Keyword::Start:
if (parent_direction == Direction::Ltr) {
style.set_property(PropertyID::TextAlign, CSSKeywordValue::create(Keyword::Left));
} else {
style.set_property(PropertyID::TextAlign, CSSKeywordValue::create(Keyword::Right));
}
break;
case Keyword::End:
if (parent_direction == Direction::Ltr) {
style.set_property(PropertyID::TextAlign, CSSKeywordValue::create(Keyword::Right));
} else {
style.set_property(PropertyID::TextAlign, CSSKeywordValue::create(Keyword::Left));
}
break;
default:
style.set_property(PropertyID::TextAlign, parent_text_align);
}
} else {
style.set_property(PropertyID::TextAlign, CSSKeywordValue::create(Keyword::Start));
}
}
}
enum class BoxTypeTransformation {
None,
Blockify,
@ -2544,8 +2588,9 @@ GC::Ref<ComputedProperties> StyleComputer::compute_properties(DOM::Element& elem
// 6. Run automatic box type transformations
transform_box_type_if_needed(computed_style, element, pseudo_element);
// 7. Resolve effective overflow values
// 7. Apply any property-specific computed value logic
resolve_effective_overflow_values(computed_style);
compute_text_align(computed_style, element, pseudo_element);
// 8. Let the element adjust computed style
element.adjust_computed_style(computed_style);

View file

@ -204,6 +204,9 @@ void LineBuilder::update_last_line()
case CSS::TextAlign::LibwebRight:
inline_offset += excess_inline_space;
break;
case CSS::TextAlign::MatchParent:
// This should have been replaced before this point.
VERIFY_NOT_REACHED();
case CSS::TextAlign::Left:
case CSS::TextAlign::LibwebLeft:
case CSS::TextAlign::Justify:

View file

@ -0,0 +1,34 @@
<!DOCTYPE html>
<head>
<style>
.left { text-align: left; }
.center { text-align: center; }
.right { text-align: right; }
</style>
</head>
<body>
<div>
<div class="left">Left</div>
<div class="left">Left</div>
</div>
<div>
<div class="center">Center</div>
<div class="center">Center</div>
</div>
<div>
<div class="right">Right</div>
<div class="right">Right</div>
</div>
<div>
<div class="right">Right</div>
<div class="right">Right</div>
</div>
<div>
<div class="center">Center</div>
<div class="center">Center</div>
</div>
<div>
<div class="left">Left</div>
<div class="left">Left</div>
</div>
</body>

View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<head>
<link rel="match" href="../../../expected/css/css-text/text-align-match-parent-ref.html" />
<style>
.outer-start { text-align: start; }
.outer-end { text-align: end; }
.outer-center { text-align: center; }
.ltr { direction: ltr; }
.rtl { direction: rtl; }
.inner { text-align: match-parent; }
</style>
</head>
<body>
<div class="outer-start ltr">
<div class="inner ltr">Left</div>
<div class="inner rtl">Left</div>
</div>
<div class="outer-center ltr">
<div class="inner ltr">Center</div>
<div class="inner rtl">Center</div>
</div>
<div class="outer-end ltr">
<div class="inner ltr">Right</div>
<div class="inner rtl">Right</div>
</div>
<div class="outer-start rtl">
<div class="inner ltr">Right</div>
<div class="inner rtl">Right</div>
</div>
<div class="outer-center rtl">
<div class="inner ltr">Center</div>
<div class="inner rtl">Center</div>
</div>
<div class="outer-end rtl">
<div class="inner ltr">Left</div>
<div class="inner rtl">Left</div>
</div>
</body>

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass CSS Text Test: text-align - computed value for match-parent on the root element

View file

@ -0,0 +1,23 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Text Test: text-align - computed value for match-parent on the root element</title>
<link rel="help" href="https://drafts.csswg.org/css-text/#valdef-text-align-match-parent">
<meta name="assert" content="'text-align: match-parent' on the root element with 'direction: rtl' should compute to 'start'.">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<style>
html {
text-align: match-parent;
direction: rtl;
}
#log {
direction: ltr;
text-align: start;
}
</style>
<div id="log"></div>
<script>
test(() => {
assert_equals(getComputedStyle(document.documentElement).textAlign, 'start');
});
</script>