mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-10-19 15:43:20 +00:00
LibWeb: Implement anchor-size(..)
function parsing
This parses `anchor-size(..)` functions in CSS, but does not yet result in a useful `Size`: we need style & layout interleaving similar to container queries for this, since the resulting value depends on layout results. Not supported yet: `anchor-size()` appearing inside a `calc()` node. Adds 4280 WPT subtest passes in `css/css-anchor-position`.
This commit is contained in:
parent
02598040ad
commit
c4f5e7bee3
Notes:
github-actions[bot]
2025-07-30 17:15:09 +00:00
Author: https://github.com/gmta
Commit: c4f5e7bee3
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5655
Reviewed-by: https://github.com/tcl3 ✅
16 changed files with 318 additions and 3 deletions
|
@ -178,6 +178,7 @@ set(SOURCES
|
|||
CSS/StyleSheet.cpp
|
||||
CSS/StyleSheetIdentifier.cpp
|
||||
CSS/StyleSheetList.cpp
|
||||
CSS/StyleValues/AnchorSizeStyleValue.cpp
|
||||
CSS/StyleValues/AngleStyleValue.cpp
|
||||
CSS/StyleValues/BackgroundRepeatStyleValue.cpp
|
||||
CSS/StyleValues/BackgroundSizeStyleValue.cpp
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <LibWeb/CSS/CSSStyleValue.h>
|
||||
#include <LibWeb/CSS/Parser/Parser.h>
|
||||
#include <LibWeb/CSS/StyleValues/AbstractImageStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/AnchorSizeStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/AngleStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/BackgroundRepeatStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/BackgroundSizeStyleValue.h>
|
||||
|
@ -83,6 +84,12 @@ AbstractImageStyleValue const& CSSStyleValue::as_abstract_image() const
|
|||
return static_cast<AbstractImageStyleValue const&>(*this);
|
||||
}
|
||||
|
||||
AnchorSizeStyleValue const& CSSStyleValue::as_anchor_size() const
|
||||
{
|
||||
VERIFY(is_anchor_size());
|
||||
return static_cast<AnchorSizeStyleValue const&>(*this);
|
||||
}
|
||||
|
||||
AngleStyleValue const& CSSStyleValue::as_angle() const
|
||||
{
|
||||
VERIFY(is_angle());
|
||||
|
|
|
@ -87,6 +87,7 @@ public:
|
|||
virtual ~CSSStyleValue() = default;
|
||||
|
||||
enum class Type {
|
||||
AnchorSize,
|
||||
Angle,
|
||||
BackgroundRepeat,
|
||||
BackgroundSize,
|
||||
|
@ -154,6 +155,10 @@ public:
|
|||
AbstractImageStyleValue const& as_abstract_image() const;
|
||||
AbstractImageStyleValue& as_abstract_image() { return const_cast<AbstractImageStyleValue&>(const_cast<CSSStyleValue const&>(*this).as_abstract_image()); }
|
||||
|
||||
bool is_anchor_size() const { return type() == Type::AnchorSize; }
|
||||
AnchorSizeStyleValue const& as_anchor_size() const;
|
||||
AnchorSizeStyleValue& as_anchor_size() { return const_cast<AnchorSizeStyleValue&>(const_cast<CSSStyleValue const&>(*this).as_anchor_size()); }
|
||||
|
||||
bool is_angle() const { return type() == Type::Angle; }
|
||||
AngleStyleValue const& as_angle() const;
|
||||
AngleStyleValue& as_angle() { return const_cast<AngleStyleValue&>(const_cast<CSSStyleValue const&>(*this).as_angle()); }
|
||||
|
|
|
@ -182,7 +182,10 @@ Size ComputedProperties::size_value(PropertyID id) const
|
|||
return Size::make_length(length);
|
||||
}
|
||||
|
||||
// FIXME: Support `fit-content(<length>)`
|
||||
// FIXME: Support `anchor-size(..)`
|
||||
if (value.is_anchor_size())
|
||||
return Size::make_none();
|
||||
|
||||
dbgln("FIXME: Unsupported size value: `{}`, treating as `auto`", value.to_string(SerializationMode::Normal));
|
||||
return Size::make_auto();
|
||||
}
|
||||
|
|
|
@ -40,6 +40,14 @@
|
|||
"stretch",
|
||||
"unsafe"
|
||||
],
|
||||
"anchor-size": [
|
||||
"block",
|
||||
"height",
|
||||
"inline",
|
||||
"self-block",
|
||||
"self-inline",
|
||||
"width"
|
||||
],
|
||||
"animation-direction": [
|
||||
"alternate",
|
||||
"alternate-reverse",
|
||||
|
|
|
@ -225,6 +225,7 @@
|
|||
"grid",
|
||||
"groove",
|
||||
"hard-light",
|
||||
"height",
|
||||
"help",
|
||||
"hide",
|
||||
"hidden",
|
||||
|
@ -447,7 +448,9 @@
|
|||
"searchfield",
|
||||
"selecteditem",
|
||||
"selecteditemtext",
|
||||
"self-block",
|
||||
"self-end",
|
||||
"self-inline",
|
||||
"self-start",
|
||||
"semi-condensed",
|
||||
"semi-expanded",
|
||||
|
@ -550,6 +553,7 @@
|
|||
"w-resize",
|
||||
"wait",
|
||||
"wavy",
|
||||
"width",
|
||||
"window",
|
||||
"windowframe",
|
||||
"windowtext",
|
||||
|
|
|
@ -396,6 +396,7 @@ private:
|
|||
RefPtr<StringStyleValue const> parse_opentype_tag_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<FontSourceStyleValue const> parse_font_source_value(TokenStream<ComponentValue>&);
|
||||
|
||||
RefPtr<CSSStyleValue const> parse_anchor_size(TokenStream<ComponentValue>&);
|
||||
RefPtr<CSSStyleValue const> parse_angle_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<CSSStyleValue const> parse_angle_percentage_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<CSSStyleValue const> parse_flex_value(TokenStream<ComponentValue>&);
|
||||
|
|
|
@ -293,7 +293,7 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
|
|||
auto transaction = tokens.begin_transaction();
|
||||
if (property_accepts_type(*property, ValueType::Percentage)) {
|
||||
if (auto value = parse_length_percentage_value(tokens)) {
|
||||
if (value->is_calculated()) {
|
||||
if (value->is_calculated() || value->is_anchor_size()) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
|
@ -308,7 +308,7 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
|
|||
}
|
||||
}
|
||||
if (auto value = parse_length_value(tokens)) {
|
||||
if (value->is_calculated()) {
|
||||
if (value->is_calculated() || value->is_anchor_size()) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
* Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
|
||||
* Copyright (c) 2024, Glenn Skrzypczak <glenn.skrzypczak@gmail.com>
|
||||
* Copyright (c) 2025, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
||||
* Copyright (c) 2025, Jelle Raaijmakers <jelle@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -21,6 +22,7 @@
|
|||
#include <LibWeb/CSS/FontFace.h>
|
||||
#include <LibWeb/CSS/Parser/ArbitrarySubstitutionFunctions.h>
|
||||
#include <LibWeb/CSS/Parser/Parser.h>
|
||||
#include <LibWeb/CSS/StyleValues/AnchorSizeStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/AngleStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/BackgroundRepeatStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/BackgroundSizeStyleValue.h>
|
||||
|
@ -266,6 +268,7 @@ Optional<LengthOrCalculated> Parser::parse_length(TokenStream<ComponentValue>& t
|
|||
return value->as_length().length();
|
||||
if (value->is_calculated())
|
||||
return LengthOrCalculated { value->as_calculated() };
|
||||
// FIXME: Deal with ->is_anchor_size()
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
@ -279,6 +282,7 @@ Optional<LengthPercentage> Parser::parse_length_percentage(TokenStream<Component
|
|||
return value->as_percentage().percentage();
|
||||
if (value->is_calculated())
|
||||
return LengthPercentage { value->as_calculated() };
|
||||
// FIXME: Deal with ->is_anchor_size()
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
@ -791,6 +795,112 @@ RefPtr<CSSStyleValue const> Parser::parse_percentage_value(TokenStream<Component
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/css-anchor-position-1/#sizing
|
||||
RefPtr<CSSStyleValue const> Parser::parse_anchor_size(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
// anchor-size() = anchor-size( [ <anchor-name> || <anchor-size> ]? , <length-percentage>? )
|
||||
|
||||
auto transaction = tokens.begin_transaction();
|
||||
auto const& function_token = tokens.consume_a_token();
|
||||
if (!function_token.is_function("anchor-size"sv))
|
||||
return {};
|
||||
|
||||
// It is only allowed in the accepted @position-try properties (and is otherwise invalid).
|
||||
static Array allowed_property_ids = {
|
||||
// inset properties
|
||||
PropertyID::Inset,
|
||||
PropertyID::Top, PropertyID::Right, PropertyID::Bottom, PropertyID::Left,
|
||||
PropertyID::InsetBlock, PropertyID::InsetBlockStart, PropertyID::InsetBlockEnd,
|
||||
PropertyID::InsetInline, PropertyID::InsetInlineStart, PropertyID::InsetInlineEnd,
|
||||
// margin properties
|
||||
PropertyID::Margin,
|
||||
PropertyID::MarginTop, PropertyID::MarginRight, PropertyID::MarginBottom, PropertyID::MarginLeft,
|
||||
PropertyID::MarginBlock, PropertyID::MarginBlockStart, PropertyID::MarginBlockEnd,
|
||||
PropertyID::MarginInline, PropertyID::MarginInlineStart, PropertyID::MarginInlineEnd,
|
||||
// sizing properties
|
||||
PropertyID::Width, PropertyID::MinWidth, PropertyID::MaxWidth,
|
||||
PropertyID::Height, PropertyID::MinHeight, PropertyID::MaxHeight,
|
||||
PropertyID::BlockSize, PropertyID::MinBlockSize, PropertyID::MaxBlockSize,
|
||||
PropertyID::InlineSize, PropertyID::MinInlineSize, PropertyID::MaxInlineSize,
|
||||
// self-alignment properties
|
||||
PropertyID::AlignSelf, PropertyID::JustifySelf, PropertyID::PlaceSelf,
|
||||
// FIXME: position-anchor
|
||||
// FIXME: position-area
|
||||
};
|
||||
bool valid_property_context = false;
|
||||
for (auto& value_context : m_value_context) {
|
||||
if (!value_context.has<PropertyID>())
|
||||
continue;
|
||||
if (!allowed_property_ids.contains_slow(value_context.get<PropertyID>())) {
|
||||
valid_property_context = false;
|
||||
break;
|
||||
}
|
||||
valid_property_context = true;
|
||||
}
|
||||
if (!valid_property_context)
|
||||
return {};
|
||||
|
||||
auto context_guard = push_temporary_value_parsing_context(FunctionContext { function_token.function().name });
|
||||
auto argument_tokens = TokenStream { function_token.function().value };
|
||||
|
||||
Optional<FlyString> anchor_name;
|
||||
Optional<AnchorSize> anchor_size;
|
||||
ValueComparingRefPtr<CSSStyleValue const> fallback_value;
|
||||
|
||||
// Parse optional anchor name and anchor size in arbitrary order.
|
||||
for (auto i = 0; i < 2; ++i) {
|
||||
argument_tokens.discard_whitespace();
|
||||
auto const& peek_token = argument_tokens.next_token();
|
||||
if (!peek_token.is(Token::Type::Ident))
|
||||
break;
|
||||
|
||||
// <anchor-name> = <dashed-ident>
|
||||
if (auto dashed_ident = parse_dashed_ident(argument_tokens); dashed_ident.has_value()) {
|
||||
if (anchor_name.has_value())
|
||||
return {};
|
||||
anchor_name = dashed_ident.value();
|
||||
continue;
|
||||
}
|
||||
|
||||
// <anchor-size> = width | height | block | inline | self-block | self-inline
|
||||
auto keyword = keyword_from_string(peek_token.token().ident());
|
||||
if (!keyword.has_value())
|
||||
return {};
|
||||
auto maybe_anchor_size = keyword_to_anchor_size(keyword.value());
|
||||
if (!maybe_anchor_size.has_value() || anchor_size.has_value())
|
||||
return {};
|
||||
argument_tokens.discard_a_token();
|
||||
anchor_size = maybe_anchor_size.release_value();
|
||||
}
|
||||
|
||||
argument_tokens.discard_whitespace();
|
||||
auto has_name_or_size = anchor_name.has_value() || anchor_size.has_value();
|
||||
auto comma_present = false;
|
||||
if (argument_tokens.next_token().is(Token::Type::Comma)) {
|
||||
if (!has_name_or_size)
|
||||
return {};
|
||||
comma_present = true;
|
||||
argument_tokens.discard_a_token();
|
||||
argument_tokens.discard_whitespace();
|
||||
}
|
||||
|
||||
// FIXME: Nested anchor sizes should actually be handled by parse_length_percentage()
|
||||
if (auto nested_anchor_size = parse_anchor_size(argument_tokens))
|
||||
fallback_value = nested_anchor_size.release_nonnull();
|
||||
else if (auto length_percentage = parse_length_percentage_value(argument_tokens))
|
||||
fallback_value = length_percentage.release_nonnull();
|
||||
|
||||
if (!fallback_value && comma_present)
|
||||
return {};
|
||||
if (fallback_value && !comma_present && has_name_or_size)
|
||||
return {};
|
||||
if (argument_tokens.has_next_token())
|
||||
return {};
|
||||
|
||||
transaction.commit();
|
||||
return AnchorSizeStyleValue::create(anchor_name, anchor_size, fallback_value);
|
||||
}
|
||||
|
||||
RefPtr<CSSStyleValue const> Parser::parse_angle_value(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
if (tokens.next_token().is(Token::Type::Dimension)) {
|
||||
|
@ -959,6 +1069,9 @@ RefPtr<CSSStyleValue const> Parser::parse_length_value(TokenStream<ComponentValu
|
|||
}
|
||||
}
|
||||
|
||||
if (tokens.next_token().is_function("anchor-size"sv))
|
||||
return parse_anchor_size(tokens);
|
||||
|
||||
auto transaction = tokens.begin_transaction();
|
||||
if (auto calc = parse_calculated_value(tokens.consume_a_token()); calc
|
||||
&& (calc->is_length() || (calc->is_calculated() && calc->as_calculated().resolves_to_length()))) {
|
||||
|
@ -1006,6 +1119,9 @@ RefPtr<CSSStyleValue const> Parser::parse_length_percentage_value(TokenStream<Co
|
|||
}
|
||||
}
|
||||
|
||||
if (tokens.next_token().is_function("anchor-size"sv))
|
||||
return parse_anchor_size(tokens);
|
||||
|
||||
auto transaction = tokens.begin_transaction();
|
||||
if (auto calc = parse_calculated_value(tokens.consume_a_token()); calc
|
||||
&& (calc->is_length() || calc->is_percentage() || (calc->is_calculated() && calc->as_calculated().resolves_to_length_percentage()))) {
|
||||
|
@ -4391,6 +4507,8 @@ NonnullRefPtr<CSSStyleValue const> Parser::resolve_unresolved_style_value(DOM::A
|
|||
RefPtr<CSSStyleValue const> Parser::parse_value(ValueType value_type, TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
switch (value_type) {
|
||||
case ValueType::AnchorSize:
|
||||
return parse_anchor_size(tokens);
|
||||
case ValueType::Angle:
|
||||
return parse_angle_value(tokens);
|
||||
case ValueType::BackgroundPosition:
|
||||
|
|
50
Libraries/LibWeb/CSS/StyleValues/AnchorSizeStyleValue.cpp
Normal file
50
Libraries/LibWeb/CSS/StyleValues/AnchorSizeStyleValue.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Jelle Raaijmakers <jelle@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/CSS/StyleValues/AnchorSizeStyleValue.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
ValueComparingNonnullRefPtr<AnchorSizeStyleValue const> AnchorSizeStyleValue::create(
|
||||
Optional<FlyString> const& anchor_name, Optional<AnchorSize> const& anchor_size,
|
||||
ValueComparingRefPtr<CSSStyleValue const> const& fallback_value)
|
||||
{
|
||||
return adopt_ref(*new (nothrow) AnchorSizeStyleValue(anchor_name, anchor_size, fallback_value));
|
||||
}
|
||||
|
||||
AnchorSizeStyleValue::AnchorSizeStyleValue(Optional<FlyString> const& anchor_name, Optional<AnchorSize> const& anchor_size,
|
||||
ValueComparingRefPtr<CSSStyleValue const> const& fallback_value)
|
||||
: StyleValueWithDefaultOperators(Type::AnchorSize)
|
||||
, m_properties { .anchor_name = anchor_name, .anchor_size = anchor_size, .fallback_value = fallback_value }
|
||||
{
|
||||
}
|
||||
|
||||
String AnchorSizeStyleValue::to_string(SerializationMode serialization_mode) const
|
||||
{
|
||||
// FIXME: Handle SerializationMode.
|
||||
StringBuilder builder;
|
||||
builder.append("anchor-size("sv);
|
||||
|
||||
if (anchor_name().has_value())
|
||||
builder.append(anchor_name().value());
|
||||
|
||||
if (anchor_size().has_value()) {
|
||||
if (anchor_name().has_value())
|
||||
builder.append(' ');
|
||||
builder.append(CSS::to_string(anchor_size().value()));
|
||||
}
|
||||
|
||||
if (fallback_value()) {
|
||||
if (anchor_name().has_value() || anchor_size().has_value())
|
||||
builder.append(", "sv);
|
||||
builder.append(fallback_value()->to_string(serialization_mode));
|
||||
}
|
||||
|
||||
builder.append(')');
|
||||
return MUST(builder.to_string());
|
||||
}
|
||||
|
||||
}
|
46
Libraries/LibWeb/CSS/StyleValues/AnchorSizeStyleValue.h
Normal file
46
Libraries/LibWeb/CSS/StyleValues/AnchorSizeStyleValue.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Jelle Raaijmakers <jelle@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <LibWeb/CSS/CSSStyleValue.h>
|
||||
#include <LibWeb/CSS/PercentageOr.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
// https://drafts.csswg.org/css-anchor-position-1/#funcdef-anchor-size
|
||||
class AnchorSizeStyleValue final : public StyleValueWithDefaultOperators<AnchorSizeStyleValue> {
|
||||
public:
|
||||
static ValueComparingNonnullRefPtr<AnchorSizeStyleValue const> create(Optional<FlyString> const& anchor_name,
|
||||
Optional<AnchorSize> const& anchor_size,
|
||||
ValueComparingRefPtr<CSSStyleValue const> const& fallback_value);
|
||||
virtual ~AnchorSizeStyleValue() override = default;
|
||||
|
||||
virtual String to_string(SerializationMode) const override;
|
||||
|
||||
bool properties_equal(AnchorSizeStyleValue const& other) const { return m_properties == other.m_properties; }
|
||||
|
||||
Optional<FlyString const&> anchor_name() const { return m_properties.anchor_name; }
|
||||
Optional<AnchorSize> anchor_size() const { return m_properties.anchor_size; }
|
||||
ValueComparingRefPtr<CSSStyleValue const> fallback_value() const
|
||||
{
|
||||
return m_properties.fallback_value;
|
||||
}
|
||||
|
||||
private:
|
||||
AnchorSizeStyleValue(Optional<FlyString> const& anchor_name, Optional<AnchorSize> const& anchor_size,
|
||||
ValueComparingRefPtr<CSSStyleValue const> const& fallback_value);
|
||||
|
||||
struct Properties {
|
||||
Optional<FlyString> anchor_name;
|
||||
Optional<AnchorSize> anchor_size;
|
||||
ValueComparingRefPtr<CSSStyleValue const> fallback_value;
|
||||
bool operator==(Properties const&) const = default;
|
||||
} m_properties;
|
||||
};
|
||||
|
||||
}
|
|
@ -11,6 +11,8 @@ namespace Web::CSS {
|
|||
|
||||
Optional<ValueType> value_type_from_string(StringView string)
|
||||
{
|
||||
if (string.equals_ignoring_ascii_case("anchor-size"sv))
|
||||
return ValueType::AnchorSize;
|
||||
if (string.equals_ignoring_ascii_case("angle"sv))
|
||||
return ValueType::Angle;
|
||||
if (string.equals_ignoring_ascii_case("background-position"sv))
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
namespace Web::CSS {
|
||||
|
||||
enum class ValueType : u8 {
|
||||
AnchorSize,
|
||||
Angle,
|
||||
BackgroundPosition,
|
||||
BasicShape,
|
||||
|
|
|
@ -190,6 +190,7 @@ class SubtleCrypto;
|
|||
namespace Web::CSS {
|
||||
|
||||
class AbstractImageStyleValue;
|
||||
class AnchorSizeStyleValue;
|
||||
class Angle;
|
||||
class AngleOrCalculated;
|
||||
class AnglePercentage;
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 21 tests
|
||||
|
||||
21 Pass
|
||||
Pass e.style['font-size'] = "anchor-size(--foo width)" should not set the property value
|
||||
Pass e.style['width'] = "anchor-size(--foo, width)" should not set the property value
|
||||
Pass e.style['width'] = "anchor-size(--foo width,)" should not set the property value
|
||||
Pass e.style['width'] = "anchor-size(--foo width height)" should not set the property value
|
||||
Pass e.style['width'] = "anchor-size(--foo width, 10px 20%)" should not set the property value
|
||||
Pass e.style['width'] = "anchor-size(--foo width, 10px, 20%)" should not set the property value
|
||||
Pass e.style['width'] = "anchor-size(--foo,)" should not set the property value
|
||||
Pass e.style['width'] = "anchor-size(, 10px)" should not set the property value
|
||||
Pass e.style['width'] = "anchor-size(foo width)" should not set the property value
|
||||
Pass e.style['width'] = "anchor-size(--foo top)" should not set the property value
|
||||
Pass e.style['width'] = "anchor-size(--foo 10em)" should not set the property value
|
||||
Pass e.style['width'] = "anchor-size(--foo 100s)" should not set the property value
|
||||
Pass e.style['width'] = "anchor-size(--foo 50%)" should not set the property value
|
||||
Pass e.style['width'] = "anchor-size(--foo width, 1)" should not set the property value
|
||||
Pass e.style['width'] = "anchor-size(--foo width, 100s)" should not set the property value
|
||||
Pass e.style['width'] = "anchor-size(--foo width, height)" should not set the property value
|
||||
Pass e.style['width'] = "anchor-size(--foo width, anchor-size(bar width))" should not set the property value
|
||||
Pass e.style['width'] = "anchor-size(--foo width, anchor(--bar top))" should not set the property value
|
||||
Pass e.style['width'] = "calc(anchor-size(foo width) + 10px + 10%)" should not set the property value
|
||||
Pass e.style['width'] = "calc(10px + 100 * anchor-size(--foo width, anchor-size(bar bottom)))" should not set the property value
|
||||
Pass e.style['width'] = "min(anchor-size(--foo width), anchor-size(--bar height), anchor(--baz top))" should not set the property value
|
|
@ -0,0 +1,42 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Tests values that are invalid at parse time for the anchor-size() function</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-size">
|
||||
<link rel="author" href="mailto:xiaochengh@chromium.org">
|
||||
<script src="../../resources/testharness.js"></script>
|
||||
<script src="../../resources/testharnessreport.js"></script>
|
||||
<script src="../../css/support/parsing-testcommon.js"></script>
|
||||
|
||||
<script>
|
||||
// anchor-size() can only be used in properties accepted in `@position-try`.
|
||||
test_invalid_value('font-size', 'anchor-size(--foo width)');
|
||||
|
||||
// Invalid parameter format
|
||||
test_invalid_value('width', 'anchor-size(--foo, width)');
|
||||
test_invalid_value('width', 'anchor-size(--foo width,)');
|
||||
test_invalid_value('width', 'anchor-size(--foo width height)');
|
||||
test_invalid_value('width', 'anchor-size(--foo width, 10px 20%)');
|
||||
test_invalid_value('width', 'anchor-size(--foo width, 10px, 20%)');
|
||||
test_invalid_value('width', 'anchor-size(--foo,)');
|
||||
test_invalid_value('width', 'anchor-size(, 10px)');
|
||||
|
||||
// Anchor name must be a dashed ident
|
||||
test_invalid_value('width', 'anchor-size(foo width)');
|
||||
|
||||
// Invalid anchor size values
|
||||
test_invalid_value('width', 'anchor-size(--foo top)');
|
||||
test_invalid_value('width', 'anchor-size(--foo 10em)');
|
||||
test_invalid_value('width', 'anchor-size(--foo 100s)');
|
||||
test_invalid_value('width', 'anchor-size(--foo 50%)');
|
||||
|
||||
// Invalid fallback values
|
||||
test_invalid_value('width', 'anchor-size(--foo width, 1)');
|
||||
test_invalid_value('width', 'anchor-size(--foo width, 100s)');
|
||||
test_invalid_value('width', 'anchor-size(--foo width, height)');
|
||||
test_invalid_value('width', 'anchor-size(--foo width, anchor-size(bar width))');
|
||||
test_invalid_value('width', 'anchor-size(--foo width, anchor(--bar top))');
|
||||
|
||||
// Invalid anchor size values in calc tree
|
||||
test_invalid_value('width', 'calc(anchor-size(foo width) + 10px + 10%)');
|
||||
test_invalid_value('width', 'calc(10px + 100 * anchor-size(--foo width, anchor-size(bar bottom)))');
|
||||
test_invalid_value('width', 'min(anchor-size(--foo width), anchor-size(--bar height), anchor(--baz top))');
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue