Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[contain-intrinsic-size] Support "auto none"
https://bugs.webkit.org/show_bug.cgi?id=258618

Reviewed by Tim Nguyen.

See:
w3c/csswg-drafts#8989

* LayoutTests/imported/w3c/web-platform-tests/css/css-sizing/contain-intrinsic-size/auto-014-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-sizing/contain-intrinsic-size/auto-014.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-sizing/contain-intrinsic-size/parsing/contain-intrinsic-size-computed-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-sizing/contain-intrinsic-size/parsing/contain-intrinsic-size-computed.html:
* LayoutTests/imported/w3c/web-platform-tests/css/css-sizing/contain-intrinsic-size/parsing/contain-intrinsic-size-invalid-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-sizing/contain-intrinsic-size/parsing/contain-intrinsic-size-invalid.html:
* LayoutTests/imported/w3c/web-platform-tests/css/css-sizing/contain-intrinsic-size/parsing/contain-intrinsic-size-valid-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-sizing/contain-intrinsic-size/parsing/contain-intrinsic-size-valid.html:
* Source/WebCore/css/CSSProperties.json:
* Source/WebCore/css/ComputedStyleExtractor.cpp:
(WebCore::valueForContainIntrinsicSize):
* Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp:
(WebCore::CSSPropertyParserHelpers::consumeContainIntrinsicSize):
* Source/WebCore/dom/Document.cpp:
(WebCore::CallbackForContainIntrinsicSize):
* Source/WebCore/rendering/RenderBox.cpp:
(WebCore::RenderBox::explicitIntrinsicInnerWidth const):
(WebCore::RenderBox::explicitIntrinsicInnerHeight const):
* Source/WebCore/rendering/style/RenderStyle.h:
* Source/WebCore/rendering/style/RenderStyleConstants.cpp:
(WebCore::operator<<):
* Source/WebCore/rendering/style/RenderStyleConstants.h:
* Source/WebCore/rendering/style/RenderStyleInlines.h:
(WebCore::RenderStyle::containIntrinsicHeightHasAuto const):
(WebCore::RenderStyle::containIntrinsicWidthHasAuto const):
(WebCore::RenderStyle::hasAutoLengthContainIntrinsicSize const):
* Source/WebCore/rendering/updating/RenderTreeUpdater.cpp:
(WebCore::RenderTreeUpdater::updateElementRenderer):
* Source/WebCore/style/StyleBuilderCustom.h:
(WebCore::Style::BuilderCustom::applyValueContainIntrinsicWidth):
(WebCore::Style::BuilderCustom::applyValueContainIntrinsicHeight):

Canonical link: https://commits.webkit.org/265617@main
  • Loading branch information
rwlbuis committed Jun 29, 2023
1 parent aec46ac commit 242f3ae
Show file tree
Hide file tree
Showing 19 changed files with 158 additions and 46 deletions.
@@ -0,0 +1,3 @@

PASS Basic usage

@@ -0,0 +1,90 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>contain-intrinsic-size: auto none</title>
<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#intrinsic-size-override">
<meta name="assert" content="Tests that 'contain-intrinsic-size: auto none' respects the auto keyword">

<style>
#target {
width: max-content;
height: max-content;
}
.cis-auto {
contain-intrinsic-size: auto none;
}
.skip-contents {
content-visibility: hidden;
}
.size-100-50 {
width: 100px;
height: 50px;
}
.size-75-25 {
width: 75px;
height: 25px;
}
</style>

<div id="log"></div>

<div id="parent">
<div id="target">
<div id="contents"></div>
</div>
</div>

<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
const parent = document.getElementById("parent");
const target = document.getElementById("target");
const contents = document.getElementById("contents");

function checkSize(expectedWidth, expectedHeight, msg) {
assert_equals(target.clientWidth, expectedWidth, msg + " - clientWidth");
assert_equals(target.clientHeight, expectedHeight, msg + " - clientHeight");
}

function nextRendering() {
return new Promise(resolve => {
requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
});
}

function cleanup() {
parent.className = "";
target.className = "";
contents.className = "";
checkSize(0, 0, "Sizing after cleanup");
}

promise_test(async function() {
this.add_cleanup(cleanup);
target.className = "cis-auto skip-contents";
contents.classList.add("size-100-50");
checkSize(0, 0, "Size containment with no last remembered size");

target.classList.remove("skip-contents");
checkSize(100, 50, "Sizing normally");

await nextRendering();
target.classList.add("skip-contents");
checkSize(100, 50, "Using last remembered size");

contents.classList.remove("size-100-50");
contents.classList.add("size-75-25");
checkSize(100, 50, "Still using last remembered size");

target.classList.remove("skip-contents");
checkSize(75, 25, "Sizing normally with different size");

target.classList.add("skip-contents");
checkSize(100, 50, "Going back to last remembered size");

target.classList.remove("skip-contents");
await nextRendering();
target.classList.add("skip-contents");
checkSize(75, 25, "Using the new last remembered size");
}, "Basic usage");
</script>
Expand Up @@ -17,4 +17,5 @@ PASS Property contain-intrinsic-height value '1px'
PASS Property contain-intrinsic-height value 'auto 1px'
PASS Property contain-intrinsic-height value '2vw'
PASS Property contain-intrinsic-height value '3vh'
PASS Property contain-intrinsic-height value 'auto none'

Expand Up @@ -40,6 +40,7 @@
test_computed_value("contain-intrinsic-height", "auto 1px");
test_computed_value("contain-intrinsic-height", "2vw", length_ref("2vw"));
test_computed_value("contain-intrinsic-height", "3vh", length_ref("3vh"));
test_computed_value("contain-intrinsic-height", "auto none");
</script>
</body>
</html>
Expand Down
Expand Up @@ -38,5 +38,4 @@ PASS e.style['contain-intrinsic-block-size'] = "1px none" should not set the pro
PASS e.style['contain-intrinsic-block-size'] = "auto 1px auto" should not set the property value
PASS e.style['contain-intrinsic-block-size'] = "20%" should not set the property value
PASS e.style['contain-intrinsic-block-size'] = "1px auto" should not set the property value
PASS e.style['contain-intrinsic-block-size'] = "auto none" should not set the property value

Expand Up @@ -55,7 +55,6 @@
test_invalid_value("contain-intrinsic-block-size", "auto 1px auto");
test_invalid_value("contain-intrinsic-block-size", "20%");
test_invalid_value("contain-intrinsic-block-size", "1px auto");
test_invalid_value("contain-intrinsic-block-size", "auto none");
</script>
</body>
</html>
Expand Down
Expand Up @@ -25,4 +25,5 @@ PASS e.style['contain-intrinsic-block-size'] = "none" should set the property va
PASS e.style['contain-intrinsic-block-size'] = "1px" should set the property value
PASS e.style['contain-intrinsic-block-size'] = "2em" should set the property value
PASS e.style['contain-intrinsic-block-size'] = "auto 1px" should set the property value
PASS e.style['contain-intrinsic-block-size'] = "auto none" should set the property value

Expand Up @@ -42,6 +42,8 @@
test_valid_value("contain-intrinsic-block-size", "1px");
test_valid_value("contain-intrinsic-block-size", "2em");
test_valid_value("contain-intrinsic-block-size", "auto 1px");

test_valid_value("contain-intrinsic-block-size", "auto none");
</script>
</body>
</html>
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/css/CSSProperties.json
Expand Up @@ -6336,7 +6336,7 @@
"resolver": "horizontal"
},
"parser-function": "consumeContainIntrinsicSize",
"parser-grammar-unused": "none | <length> | [ auto && <length> ]",
"parser-grammar-unused": "auto? [none | <<length>>]",
"parser-grammar-unused-reason": "Needs support for '&&' groups.",
"comment": "Should ensure generator simplifies to 'none | [ <length> && auto? ]"
},
Expand All @@ -6354,7 +6354,7 @@
"resolver": "block"
},
"parser-function": "consumeContainIntrinsicSize",
"parser-grammar-unused": "none | <length> | [ auto && <length> ]",
"parser-grammar-unused": "auto? [none | <<length>>]",
"parser-grammar-unused-reason": "Needs support for '&&' groups.",
"comment": "Should ensure generator simplifies to 'none | [ <length> && auto? ]"
},
Expand Down
2 changes: 2 additions & 0 deletions Source/WebCore/css/ComputedStyleExtractor.cpp
Expand Up @@ -1747,6 +1747,8 @@ static Ref<CSSValue> valueForContainIntrinsicSize(const RenderStyle& style, cons
case ContainIntrinsicSizeType::AutoAndLength:
return CSSValueList::createSpaceSeparated(CSSPrimitiveValue::create(CSSValueAuto),
zoomAdjustedPixelValueForLength(containIntrinsicLength.value(), style));
case ContainIntrinsicSizeType::AutoAndNone:
return CSSValueList::createSpaceSeparated(CSSPrimitiveValue::create(CSSValueAuto), CSSPrimitiveValue::create(CSSValueNone));
}
RELEASE_ASSERT_NOT_REACHED();
return CSSPrimitiveValue::create(CSSValueNone);
Expand Down
30 changes: 12 additions & 18 deletions Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp
Expand Up @@ -8097,29 +8097,23 @@ RefPtr<CSSValue> consumeContain(CSSParserTokenRange& range)
RefPtr<CSSValue> consumeContainIntrinsicSize(CSSParserTokenRange& range)
{
RefPtr<CSSPrimitiveValue> autoValue;
if (range.peek().type() == IdentToken) {
switch (range.peek().id()) {
case CSSValueNone:
return consumeIdent<CSSValueNone>(range);
case CSSValueAuto:
autoValue = consumeIdent<CSSValueAuto>(range);
break;
default:
if ((autoValue = consumeIdent<CSSValueAuto>(range))) {
if (range.atEnd())
return nullptr;
}
}

if (range.atEnd())
return nullptr;

auto lengthValue = consumeLength(range, HTMLStandardMode, ValueRange::NonNegative);
if (!lengthValue)
return nullptr;
if (auto noneValue = consumeIdent<CSSValueNone>(range)) {
if (autoValue)
return CSSValuePair::create(autoValue.releaseNonNull(), noneValue.releaseNonNull());
return noneValue;
}

if (!autoValue)
if (auto lengthValue = consumeLength(range, HTMLStandardMode, ValueRange::NonNegative)) {
if (autoValue)
return CSSValuePair::create(autoValue.releaseNonNull(), lengthValue.releaseNonNull());
return lengthValue;

return CSSValueList::createSpaceSeparated(autoValue.releaseNonNull(), lengthValue.releaseNonNull());
}
return nullptr;
}

RefPtr<CSSValue> consumeTextEmphasisPosition(CSSParserTokenRange& range)
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/dom/Document.cpp
Expand Up @@ -416,9 +416,9 @@ static void CallbackForContainIntrinsicSize(const Vector<Ref<ResizeObserverEntry
ASSERT(box->style().hasAutoLengthContainIntrinsicSize());

auto contentBoxSize = entry->contentBoxSize().at(0);
if (box->style().containIntrinsicLogicalWidthType() == ContainIntrinsicSizeType::AutoAndLength)
if (box->style().containIntrinsicWidthHasAuto())
target->setLastRememberedLogicalWidth(LayoutUnit(contentBoxSize->inlineSize()));
if (box->style().containIntrinsicLogicalHeightType() == ContainIntrinsicSizeType::AutoAndLength)
if (box->style().containIntrinsicHeightHasAuto())
target->setLastRememberedLogicalHeight(LayoutUnit(contentBoxSize->blockSize()));
}
}
Expand Down
10 changes: 8 additions & 2 deletions Source/WebCore/rendering/RenderBox.cpp
Expand Up @@ -5676,11 +5676,14 @@ std::optional<LayoutUnit> RenderBox::explicitIntrinsicInnerWidth() const
if (style().containIntrinsicWidthType() == ContainIntrinsicSizeType::None)
return std::nullopt;

if (element() && style().containIntrinsicWidthType() == ContainIntrinsicSizeType::AutoAndLength && shouldSkipContent()) {
if (element() && style().containIntrinsicWidthHasAuto() && shouldSkipContent()) {
if (auto width = isHorizontalWritingMode() ? element()->lastRememberedLogicalWidth() : element()->lastRememberedLogicalHeight())
return width;
}

if (style().containIntrinsicWidthType() == ContainIntrinsicSizeType::AutoAndNone)
return std::nullopt;

auto width = style().containIntrinsicWidth();
ASSERT(width.has_value());
return std::optional<LayoutUnit> { width->value() };
Expand All @@ -5692,11 +5695,14 @@ std::optional<LayoutUnit> RenderBox::explicitIntrinsicInnerHeight() const
if (style().containIntrinsicHeightType() == ContainIntrinsicSizeType::None)
return std::nullopt;

if (element() && style().containIntrinsicHeightType() == ContainIntrinsicSizeType::AutoAndLength && shouldSkipContent()) {
if (element() && style().containIntrinsicHeightHasAuto() && shouldSkipContent()) {
if (auto height = isHorizontalWritingMode() ? element()->lastRememberedLogicalHeight() : element()->lastRememberedLogicalWidth())
return height;
}

if (style().containIntrinsicHeightType() == ContainIntrinsicSizeType::AutoAndNone)
return std::nullopt;

auto height = style().containIntrinsicHeight();
ASSERT(height.has_value());
return std::optional<LayoutUnit> { height->value() };
Expand Down
2 changes: 2 additions & 0 deletions Source/WebCore/rendering/style/RenderStyle.h
Expand Up @@ -702,6 +702,8 @@ class RenderStyle {
inline ContainIntrinsicSizeType containIntrinsicHeightType() const;
inline ContainIntrinsicSizeType containIntrinsicLogicalWidthType() const;
inline ContainIntrinsicSizeType containIntrinsicLogicalHeightType() const;
inline bool containIntrinsicWidthHasAuto() const;
inline bool containIntrinsicHeightHasAuto() const;
inline std::optional<Length> containIntrinsicWidth() const;
inline std::optional<Length> containIntrinsicHeight() const;
inline bool hasAutoLengthContainIntrinsicSize() const;
Expand Down
3 changes: 3 additions & 0 deletions Source/WebCore/rendering/style/RenderStyleConstants.cpp
Expand Up @@ -1351,6 +1351,9 @@ TextStream& operator<<(TextStream& ts, ContainIntrinsicSizeType containIntrinsic
case ContainIntrinsicSizeType::AutoAndLength:
ts << "autoandlength";
break;
case ContainIntrinsicSizeType::AutoAndNone:
ts << "autoandnone";
break;
}
return ts;
}
Expand Down
3 changes: 2 additions & 1 deletion Source/WebCore/rendering/style/RenderStyleConstants.h
Expand Up @@ -1152,7 +1152,8 @@ enum class ContainerType : uint8_t {
enum class ContainIntrinsicSizeType : uint8_t {
None,
Length,
AutoAndLength
AutoAndLength,
AutoAndNone,
};

enum class ContentVisibility : uint8_t {
Expand Down
4 changes: 3 additions & 1 deletion Source/WebCore/rendering/style/RenderStyleInlines.h
Expand Up @@ -169,8 +169,10 @@ inline const AtomString& RenderStyle::computedLocale() const { return fontDescri
inline OptionSet<Containment> RenderStyle::contain() const { return m_nonInheritedData->rareData->contain; }
inline std::optional<Length> RenderStyle::containIntrinsicHeight() const { return m_nonInheritedData->rareData->containIntrinsicHeight; }
inline ContainIntrinsicSizeType RenderStyle::containIntrinsicHeightType() const { return static_cast<ContainIntrinsicSizeType>(m_nonInheritedData->rareData->containIntrinsicHeightType); }
inline bool RenderStyle::containIntrinsicHeightHasAuto() const { return containIntrinsicHeightType() == ContainIntrinsicSizeType::AutoAndLength || containIntrinsicHeightType() == ContainIntrinsicSizeType::AutoAndNone; }
inline ContainIntrinsicSizeType RenderStyle::containIntrinsicLogicalHeightType() const { return isHorizontalWritingMode() ? containIntrinsicHeightType() : containIntrinsicWidthType(); }
inline ContainIntrinsicSizeType RenderStyle::containIntrinsicLogicalWidthType() const { return isHorizontalWritingMode() ? containIntrinsicWidthType() : containIntrinsicHeightType(); }
inline bool RenderStyle::containIntrinsicWidthHasAuto() const { return containIntrinsicWidthType() == ContainIntrinsicSizeType::AutoAndLength || containIntrinsicWidthType() == ContainIntrinsicSizeType::AutoAndNone; }
inline std::optional<Length> RenderStyle::containIntrinsicWidth() const { return m_nonInheritedData->rareData->containIntrinsicWidth; }
inline ContainIntrinsicSizeType RenderStyle::containIntrinsicWidthType() const { return static_cast<ContainIntrinsicSizeType>(m_nonInheritedData->rareData->containIntrinsicWidthType); }
inline const Vector<AtomString>& RenderStyle::containerNames() const { return m_nonInheritedData->rareData->containerNames; }
Expand Down Expand Up @@ -252,7 +254,7 @@ inline bool RenderStyle::hasAutoCaretColor() const { return m_rareInheritedData-
inline bool RenderStyle::hasAutoColumnCount() const { return m_nonInheritedData->miscData->multiCol->autoCount; }
inline bool RenderStyle::hasAutoColumnWidth() const { return m_nonInheritedData->miscData->multiCol->autoWidth; }
inline bool RenderStyle::hasAutoLeftAndRight() const { return left().isAuto() && right().isAuto(); }
inline bool RenderStyle::hasAutoLengthContainIntrinsicSize() const { return containIntrinsicWidthType() == ContainIntrinsicSizeType::AutoAndLength || containIntrinsicHeightType() == ContainIntrinsicSizeType::AutoAndLength; }
inline bool RenderStyle::hasAutoLengthContainIntrinsicSize() const { return containIntrinsicWidthHasAuto() || containIntrinsicHeightHasAuto(); }
inline bool RenderStyle::hasAutoOrphans() const { return m_rareInheritedData->hasAutoOrphans; }
inline bool RenderStyle::hasAutoSpecifiedZIndex() const { return m_nonInheritedData->boxData->hasAutoSpecifiedZIndex(); }
inline bool RenderStyle::hasAutoTopAndBottom() const { return top().isAuto() && bottom().isAuto(); }
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/rendering/updating/RenderTreeUpdater.cpp
Expand Up @@ -349,9 +349,9 @@ void RenderTreeUpdater::updateElementRenderer(Element& element, const Style::Ele
element.clearDisplayContentsStyle();

if (!hasDisplayContents) {
if (elementUpdateStyle.containIntrinsicLogicalWidthType() != ContainIntrinsicSizeType::AutoAndLength)
if (!elementUpdateStyle.containIntrinsicWidthHasAuto())
element.clearLastRememberedLogicalWidth();
if (elementUpdateStyle.containIntrinsicLogicalHeightType() != ContainIntrinsicSizeType::AutoAndLength)
if (!elementUpdateStyle.containIntrinsicHeightHasAuto())
element.clearLastRememberedLogicalHeight();
}
auto scopeExit = makeScopeExit([&] {
Expand Down
38 changes: 22 additions & 16 deletions Source/WebCore/style/StyleBuilderCustom.h
Expand Up @@ -2095,16 +2095,19 @@ inline void BuilderCustom::applyValueContainIntrinsicWidth(BuilderState& builder
return;
}

if (!is<CSSValueList>(value))
if (!is<CSSValuePair>(value))
return;

auto& list = downcast<CSSValueList>(value);
ASSERT(list.length() == 2);
ASSERT(downcast<CSSPrimitiveValue>(list.item(0))->valueID() == CSSValueAuto);
ASSERT(downcast<CSSPrimitiveValue>(list.item(1))->isLength());
style.setContainIntrinsicWidthType(ContainIntrinsicSizeType::AutoAndLength);
auto lengthValue = downcast<CSSPrimitiveValue>(list.item(1))->computeLength<Length>(builderState.cssToLengthConversionData().copyWithAdjustedZoom(1.0f));
style.setContainIntrinsicWidth(lengthValue);
auto& pair = downcast<CSSValuePair>(value);
ASSERT(downcast<CSSPrimitiveValue>(pair.first()).valueID() == CSSValueAuto);
ASSERT(downcast<CSSPrimitiveValue>(pair.second()).isLength() || downcast<CSSPrimitiveValue>(pair.second()).valueID() == CSSValueNone);
if (downcast<CSSPrimitiveValue>(pair.second()).valueID() == CSSValueNone)
style.setContainIntrinsicWidthType(ContainIntrinsicSizeType::AutoAndNone);
else {
style.setContainIntrinsicWidthType(ContainIntrinsicSizeType::AutoAndLength);
auto lengthValue = downcast<CSSPrimitiveValue>(pair.second()).computeLength<Length>(builderState.cssToLengthConversionData().copyWithAdjustedZoom(1.0f));
style.setContainIntrinsicWidth(lengthValue);
}
}

inline void BuilderCustom::applyInitialContainIntrinsicHeight(BuilderState& builderState)
Expand Down Expand Up @@ -2135,16 +2138,19 @@ inline void BuilderCustom::applyValueContainIntrinsicHeight(BuilderState& builde
return;
}

if (!is<CSSValueList>(value))
if (!is<CSSValuePair>(value))
return;

auto& list = downcast<CSSValueList>(value);
ASSERT(list.length() == 2);
ASSERT(downcast<CSSPrimitiveValue>(list.item(0))->valueID() == CSSValueAuto);
ASSERT(downcast<CSSPrimitiveValue>(list.item(1))->isLength());
style.setContainIntrinsicHeightType(ContainIntrinsicSizeType::AutoAndLength);
auto lengthValue = downcast<CSSPrimitiveValue>(list.item(1))->computeLength<Length>(builderState.cssToLengthConversionData().copyWithAdjustedZoom(1.0f));
style.setContainIntrinsicHeight(lengthValue);
auto& pair = downcast<CSSValuePair>(value);
ASSERT(downcast<CSSPrimitiveValue>(pair.first()).valueID() == CSSValueAuto);
ASSERT(downcast<CSSPrimitiveValue>(pair.second()).isLength() || downcast<CSSPrimitiveValue>(pair.second()).valueID() == CSSValueNone);
if (downcast<CSSPrimitiveValue>(pair.second()).valueID() == CSSValueNone)
style.setContainIntrinsicHeightType(ContainIntrinsicSizeType::AutoAndNone);
else {
style.setContainIntrinsicHeightType(ContainIntrinsicSizeType::AutoAndLength);
auto lengthValue = downcast<CSSPrimitiveValue>(pair.second()).computeLength<Length>(builderState.cssToLengthConversionData().copyWithAdjustedZoom(1.0f));
style.setContainIntrinsicHeight(lengthValue);
}
}

}
Expand Down

0 comments on commit 242f3ae

Please sign in to comment.