Commit 88340632 authored by Oriol Brufau's avatar Oriol Brufau Committed by Commit Bot

[css-pseudo] Don't update non-normal markers if list-style-type changes

If a ::marker has the 'content' property set to something different than
'normal', then the contents of the marker should be determined according
to that value, not from 'list-style-type'.

Before this patch, the behavior was already correct when laying out the
marker for the first time. But if 'list-style-type' changed afterwards,
the marker was updated to reflect the new value, ignoring 'content'.

BUG=457718

TEST=external/wpt/css/css-pseudo/marker-content-021.html

The test fails in legacy since 'content' is not supported yet.

Change-Id: Id845774739927c9c574a66e9d1cc94e6ea59d5e5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2020957Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Commit-Queue: Oriol Brufau <obrufau@igalia.com>
Cr-Commit-Position: refs/heads/master@{#736105}
parent 86c1eb34
...@@ -12,8 +12,7 @@ ...@@ -12,8 +12,7 @@
namespace blink { namespace blink {
ListMarker::ListMarker() ListMarker::ListMarker() : marker_text_type_(kNotText) {}
: marker_type_(kStatic), is_marker_text_updated_(false) {}
const ListMarker* ListMarker::Get(const LayoutObject* object) { const ListMarker* ListMarker::Get(const LayoutObject* object) {
if (!object) if (!object)
...@@ -33,17 +32,17 @@ ListMarker* ListMarker::Get(LayoutObject* object) { ...@@ -33,17 +32,17 @@ ListMarker* ListMarker::Get(LayoutObject* object) {
// If the value of ListStyleType changed, we need to the marker text has been // If the value of ListStyleType changed, we need to the marker text has been
// updated. // updated.
void ListMarker::ListStyleTypeChanged(LayoutObject& marker) { void ListMarker::ListStyleTypeChanged(LayoutObject& marker) {
if (!is_marker_text_updated_) if (marker_text_type_ == kNotText || marker_text_type_ == kUnresolved)
return; return;
is_marker_text_updated_ = false; marker_text_type_ = kUnresolved;
marker.SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation( marker.SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kListStyleTypeChange); layout_invalidation_reason::kListStyleTypeChange);
} }
void ListMarker::OrdinalValueChanged(LayoutObject& marker) { void ListMarker::OrdinalValueChanged(LayoutObject& marker) {
if (marker_type_ == kOrdinalValue && is_marker_text_updated_) { if (marker_text_type_ == kOrdinalValue) {
is_marker_text_updated_ = false; marker_text_type_ = kUnresolved;
marker.SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation( marker.SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kListValueChange); layout_invalidation_reason::kListValueChange);
} }
...@@ -51,10 +50,12 @@ void ListMarker::OrdinalValueChanged(LayoutObject& marker) { ...@@ -51,10 +50,12 @@ void ListMarker::OrdinalValueChanged(LayoutObject& marker) {
void ListMarker::UpdateMarkerText(LayoutObject& marker, LayoutText* text) { void ListMarker::UpdateMarkerText(LayoutObject& marker, LayoutText* text) {
DCHECK(text); DCHECK(text);
DCHECK_EQ(marker_text_type_, kUnresolved);
StringBuilder marker_text_builder; StringBuilder marker_text_builder;
marker_type_ = MarkerText(marker, &marker_text_builder, kWithSuffix); marker_text_type_ = MarkerText(marker, &marker_text_builder, kWithSuffix);
text->SetTextIfNeeded(marker_text_builder.ToString().ReleaseImpl()); text->SetTextIfNeeded(marker_text_builder.ToString().ReleaseImpl());
is_marker_text_updated_ = true; DCHECK_NE(marker_text_type_, kNotText);
DCHECK_NE(marker_text_type_, kUnresolved);
} }
void ListMarker::UpdateMarkerText(LayoutObject& marker) { void ListMarker::UpdateMarkerText(LayoutObject& marker) {
...@@ -65,20 +66,21 @@ LayoutNGListItem* ListMarker::ListItem(const LayoutObject& marker) { ...@@ -65,20 +66,21 @@ LayoutNGListItem* ListMarker::ListItem(const LayoutObject& marker) {
return ToLayoutNGListItem(marker.GetNode()->parentNode()->GetLayoutObject()); return ToLayoutNGListItem(marker.GetNode()->parentNode()->GetLayoutObject());
} }
ListMarker::MarkerType ListMarker::MarkerText(const LayoutObject& marker, ListMarker::MarkerTextType ListMarker::MarkerText(
StringBuilder* text, const LayoutObject& marker,
MarkerTextFormat format) const { StringBuilder* text,
MarkerTextFormat format) const {
if (IsMarkerImage(marker)) { if (IsMarkerImage(marker)) {
if (format == kWithSuffix) if (format == kWithSuffix)
text->Append(' '); text->Append(' ');
return kStatic; return kNotText;
} }
LayoutNGListItem* list_item = ListItem(marker); LayoutNGListItem* list_item = ListItem(marker);
const ComputedStyle& style = list_item->StyleRef(); const ComputedStyle& style = list_item->StyleRef();
switch (style.ListStyleType()) { switch (style.ListStyleType()) {
case EListStyleType::kNone: case EListStyleType::kNone:
return kStatic; return kNotText;
case EListStyleType::kString: { case EListStyleType::kString: {
text->Append(style.ListStyleStringValue()); text->Append(style.ListStyleStringValue());
return kStatic; return kStatic;
...@@ -181,8 +183,7 @@ void ListMarker::UpdateMarkerContentIfNeeded(LayoutObject& marker) { ...@@ -181,8 +183,7 @@ void ListMarker::UpdateMarkerContentIfNeeded(LayoutObject& marker) {
// There should be at most one child. // There should be at most one child.
DCHECK(!child || !child->SlowFirstChild()); DCHECK(!child || !child->SlowFirstChild());
if (!marker.StyleRef().ContentBehavesAsNormal()) { if (!marker.StyleRef().ContentBehavesAsNormal()) {
marker_type_ = kStatic; marker_text_type_ = kNotText;
is_marker_text_updated_ = true;
} else if (IsMarkerImage(marker)) { } else if (IsMarkerImage(marker)) {
StyleImage* list_style_image = list_item->StyleRef().ListStyleImage(); StyleImage* list_style_image = list_item->StyleRef().ListStyleImage();
if (child) { if (child) {
...@@ -207,9 +208,9 @@ void ListMarker::UpdateMarkerContentIfNeeded(LayoutObject& marker) { ...@@ -207,9 +208,9 @@ void ListMarker::UpdateMarkerContentIfNeeded(LayoutObject& marker) {
image->SetIsGeneratedContent(); image->SetIsGeneratedContent();
marker.AddChild(image); marker.AddChild(image);
} }
marker_text_type_ = kNotText;
} else if (list_item->StyleRef().ListStyleType() == EListStyleType::kNone) { } else if (list_item->StyleRef().ListStyleType() == EListStyleType::kNone) {
marker_type_ = kStatic; marker_text_type_ = kNotText;
is_marker_text_updated_ = true;
} else { } else {
// Create a LayoutText in it. // Create a LayoutText in it.
LayoutText* text = nullptr; LayoutText* text = nullptr;
...@@ -232,14 +233,14 @@ void ListMarker::UpdateMarkerContentIfNeeded(LayoutObject& marker) { ...@@ -232,14 +233,14 @@ void ListMarker::UpdateMarkerContentIfNeeded(LayoutObject& marker) {
text = LayoutText::CreateEmptyAnonymous(marker.GetDocument(), text_style, text = LayoutText::CreateEmptyAnonymous(marker.GetDocument(), text_style,
LegacyLayout::kAuto); LegacyLayout::kAuto);
marker.AddChild(text); marker.AddChild(text);
is_marker_text_updated_ = false; marker_text_type_ = kUnresolved;
} }
} }
} }
LayoutObject* ListMarker::SymbolMarkerLayoutText( LayoutObject* ListMarker::SymbolMarkerLayoutText(
const LayoutObject& marker) const { const LayoutObject& marker) const {
if (marker_type_ != kSymbolValue) if (marker_text_type_ != kSymbolValue)
return nullptr; return nullptr;
return marker.SlowFirstChild(); return marker.SlowFirstChild();
} }
......
...@@ -34,7 +34,7 @@ class CORE_EXPORT ListMarker { ...@@ -34,7 +34,7 @@ class CORE_EXPORT ListMarker {
} }
void UpdateMarkerTextIfNeeded(LayoutObject& marker) { void UpdateMarkerTextIfNeeded(LayoutObject& marker) {
if (!is_marker_text_updated_ && !IsMarkerImage(marker)) if (marker_text_type_ == kUnresolved)
UpdateMarkerText(marker); UpdateMarkerText(marker);
} }
void UpdateMarkerContentIfNeeded(LayoutObject&); void UpdateMarkerContentIfNeeded(LayoutObject&);
...@@ -45,17 +45,25 @@ class CORE_EXPORT ListMarker { ...@@ -45,17 +45,25 @@ class CORE_EXPORT ListMarker {
private: private:
enum MarkerTextFormat { kWithSuffix, kWithoutSuffix }; enum MarkerTextFormat { kWithSuffix, kWithoutSuffix };
enum MarkerType { kStatic, kOrdinalValue, kSymbolValue }; enum MarkerTextType {
MarkerType MarkerText(const LayoutObject&, kNotText, // The marker doesn't have a LayoutText, either because it has
StringBuilder*, // not been created yet or because 'list-style-type' is 'none',
MarkerTextFormat) const; // 'list-style-image' is not 'none', or 'content' is not
// 'normal'.
kUnresolved, // The marker has a LayoutText that needs to be updated.
kOrdinalValue, // The marker text depends on the ordinal.
kStatic, // The marker text doesn't depend on the ordinal.
kSymbolValue, // Like kStatic, but the marker is painted as a symbol.
};
MarkerTextType MarkerText(const LayoutObject&,
StringBuilder*,
MarkerTextFormat) const;
void UpdateMarkerText(LayoutObject&); void UpdateMarkerText(LayoutObject&);
void UpdateMarkerText(LayoutObject&, LayoutText*); void UpdateMarkerText(LayoutObject&, LayoutText*);
void ListStyleTypeChanged(LayoutObject&); void ListStyleTypeChanged(LayoutObject&);
unsigned marker_type_ : 2; // Type unsigned marker_text_type_ : 3; // MarkerTextType
unsigned is_marker_text_updated_ : 1;
}; };
} // namespace blink } // namespace blink
......
...@@ -84,6 +84,7 @@ crbug.com/457718 external/wpt/css/css-pseudo/marker-content-017.html [ Failure ] ...@@ -84,6 +84,7 @@ crbug.com/457718 external/wpt/css/css-pseudo/marker-content-017.html [ Failure ]
crbug.com/457718 external/wpt/css/css-pseudo/marker-content-018.html [ Failure ] crbug.com/457718 external/wpt/css/css-pseudo/marker-content-018.html [ Failure ]
crbug.com/457718 external/wpt/css/css-pseudo/marker-content-019.html [ Failure ] crbug.com/457718 external/wpt/css/css-pseudo/marker-content-019.html [ Failure ]
crbug.com/457718 external/wpt/css/css-pseudo/marker-content-020.html [ Failure ] crbug.com/457718 external/wpt/css/css-pseudo/marker-content-020.html [ Failure ]
crbug.com/457718 external/wpt/css/css-pseudo/marker-content-021.html [ Failure ]
crbug.com/1012289 external/wpt/css/css-pseudo/marker-unicode-bidi-default.html [ Failure ] crbug.com/1012289 external/wpt/css/css-pseudo/marker-unicode-bidi-default.html [ Failure ]
crbug.com/1012289 external/wpt/css/css-pseudo/marker-unicode-bidi-normal.html [ Failure ] crbug.com/1012289 external/wpt/css/css-pseudo/marker-unicode-bidi-normal.html [ Failure ]
......
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference: ::marker pseudo elements styled with 'content' property</title>
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
<style>
::marker {
content: "[m]";
}
.inside {
list-style-position: inside;
}
</style>
<ol class="inside">
<li>inside none→symbol</li>
<li>inside symbol→decimal</li>
<li>inside decimal→roman</li>
<li>inside roman→string</li>
<li>inside string→none</li>
</ol>
<ol class="outside">
<li>outside none→symbol</li>
<li>outside symbol→decimal</li>
<li>outside decimal→roman</li>
<li>outside roman→string</li>
<li>outside string→none</li>
</ol>
<!DOCTYPE html>
<html class="reftest-wait">
<meta charset="utf-8">
<title>CSS Test: ::marker pseudo elements styled with 'content' property</title>
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
<link rel="match" href="marker-content-021-ref.html">
<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo">
<link rel="help" href="https://drafts.csswg.org/css-lists/#content-property">
<meta name="assert" content="Checks that non-normal ::marker is not updated when 'list-style-type' changes dynamically.">
<style>
::marker {
content: "[m]";
}
.inside {
list-style-position: inside;
}
.none {
list-style-type: none;
}
.symbol {
list-style-type: disc;
}
.decimal {
list-style-type: decimal;
}
.roman {
list-style-type: lower-roman;
}
.string {
list-style-type: "string";
}
</style>
<ol class="inside">
<li class="none">inside none→symbol</li>
<li class="symbol">inside symbol→decimal</li>
<li class="decimal">inside decimal→roman</li>
<li class="roman">inside roman→string</li>
<li class="string">inside string→none</li>
</ol>
<ol class="outside">
<li class="none">outside none→symbol</li>
<li class="symbol">outside symbol→decimal</li>
<li class="decimal">outside decimal→roman</li>
<li class="roman">outside roman→string</li>
<li class="string">outside string→none</li>
</ol>
<script src="/common/reftest-wait.js"></script>
<script>
"use strict";
// Use a "load" event listener and requestAnimationFrame to ensure that
// the markers will have been laid out.
addEventListener("load", function() {
requestAnimationFrame(() => {
for (let list of document.querySelectorAll("ol")) {
// Rotate class names among list items
const firstClass = list.firstElementChild.className;
for (let item of list.children) {
const next = item.nextElementSibling;
item.className = next ? next.className : firstClass;
}
}
takeScreenshot();
});
}, {once: true});
</script>
</html>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment