mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-10-03 14:50:02 +00:00
LibWeb: Parse anchor()
function for inset properties
This commit is contained in:
parent
ba6b82464c
commit
1d9e4a6f62
Notes:
github-actions[bot]
2025-08-03 20:10:50 +00:00
Author: https://github.com/tcl3
Commit: 1d9e4a6f62
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5691
Reviewed-by: https://github.com/gmta ✅
17 changed files with 2725 additions and 5 deletions
|
@ -178,6 +178,7 @@ set(SOURCES
|
|||
CSS/StyleSheet.cpp
|
||||
CSS/StyleSheetIdentifier.cpp
|
||||
CSS/StyleSheetList.cpp
|
||||
CSS/StyleValues/AnchorStyleValue.cpp
|
||||
CSS/StyleValues/AnchorSizeStyleValue.cpp
|
||||
CSS/StyleValues/AngleStyleValue.cpp
|
||||
CSS/StyleValues/BackgroundRepeatStyleValue.cpp
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <LibWeb/CSS/Parser/Parser.h>
|
||||
#include <LibWeb/CSS/StyleValues/AbstractImageStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/AnchorSizeStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/AnchorStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/AngleStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/BackgroundRepeatStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/BackgroundSizeStyleValue.h>
|
||||
|
@ -84,6 +85,12 @@ AbstractImageStyleValue const& CSSStyleValue::as_abstract_image() const
|
|||
return static_cast<AbstractImageStyleValue const&>(*this);
|
||||
}
|
||||
|
||||
AnchorStyleValue const& CSSStyleValue::as_anchor() const
|
||||
{
|
||||
VERIFY(is_anchor());
|
||||
return static_cast<AnchorStyleValue const&>(*this);
|
||||
}
|
||||
|
||||
AnchorSizeStyleValue const& CSSStyleValue::as_anchor_size() const
|
||||
{
|
||||
VERIFY(is_anchor_size());
|
||||
|
|
|
@ -87,6 +87,7 @@ public:
|
|||
virtual ~CSSStyleValue() = default;
|
||||
|
||||
enum class Type {
|
||||
Anchor,
|
||||
AnchorSize,
|
||||
Angle,
|
||||
BackgroundRepeat,
|
||||
|
@ -155,6 +156,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() const { return type() == Type::Anchor; }
|
||||
AnchorStyleValue const& as_anchor() const;
|
||||
AnchorStyleValue& as_anchor() { return const_cast<AnchorStyleValue&>(const_cast<CSSStyleValue const&>(*this).as_anchor()); }
|
||||
|
||||
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()); }
|
||||
|
|
|
@ -40,6 +40,19 @@
|
|||
"stretch",
|
||||
"unsafe"
|
||||
],
|
||||
"anchor-side": [
|
||||
"inside",
|
||||
"outside",
|
||||
"top",
|
||||
"left",
|
||||
"right",
|
||||
"bottom",
|
||||
"start",
|
||||
"end",
|
||||
"self-start",
|
||||
"self-end",
|
||||
"center"
|
||||
],
|
||||
"anchor-size": [
|
||||
"block",
|
||||
"height",
|
||||
|
|
|
@ -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(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>&);
|
||||
|
|
|
@ -384,6 +384,9 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
|
|||
if (auto parsed = parse_for_type(ValueType::Paint); parsed.has_value())
|
||||
return parsed.release_value();
|
||||
|
||||
if (auto parsed = parse_for_type(ValueType::Anchor); parsed.has_value())
|
||||
return parsed.release_value();
|
||||
|
||||
return OptionalNone {};
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <LibWeb/CSS/Parser/ArbitrarySubstitutionFunctions.h>
|
||||
#include <LibWeb/CSS/Parser/Parser.h>
|
||||
#include <LibWeb/CSS/StyleValues/AnchorSizeStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/AnchorStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/AngleStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/BackgroundRepeatStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/BackgroundSizeStyleValue.h>
|
||||
|
@ -795,6 +796,75 @@ RefPtr<CSSStyleValue const> Parser::parse_percentage_value(TokenStream<Component
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/css-anchor-position-1/#funcdef-anchor
|
||||
RefPtr<CSSStyleValue const> Parser::parse_anchor(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
// <anchor()> = anchor( <anchor-name>? && <anchor-side>, <length-percentage>? )
|
||||
|
||||
auto transaction = tokens.begin_transaction();
|
||||
auto const& function_token = tokens.consume_a_token();
|
||||
if (!function_token.is_function("anchor"sv))
|
||||
return {};
|
||||
|
||||
auto argument_tokens = TokenStream { function_token.function().value };
|
||||
auto context_guard = push_temporary_value_parsing_context(FunctionContext { function_token.function().name });
|
||||
Optional<FlyString> anchor_name;
|
||||
RefPtr<CSSStyleValue const> anchor_side_value;
|
||||
RefPtr<CSSStyleValue const> fallback_value;
|
||||
for (auto i = 0; i < 2; ++i) {
|
||||
argument_tokens.discard_whitespace();
|
||||
|
||||
// <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;
|
||||
}
|
||||
|
||||
if (anchor_side_value)
|
||||
break;
|
||||
|
||||
// <anchor-side> = inside | outside
|
||||
// | top | left | right | bottom
|
||||
// | start | end | self-start | self-end
|
||||
// | <percentage> | center
|
||||
anchor_side_value = parse_keyword_value(argument_tokens);
|
||||
if (!anchor_side_value) {
|
||||
// FIXME: Only percentages are allowed here, but we parse a length-percentage so that calc values are handled.
|
||||
anchor_side_value = parse_length_percentage_value(argument_tokens);
|
||||
if (!anchor_side_value)
|
||||
return {};
|
||||
|
||||
if (anchor_side_value->is_length())
|
||||
return {};
|
||||
|
||||
} else if (auto anchor_side_keyword = keyword_to_anchor_side(anchor_side_value->to_keyword()); !anchor_side_keyword.has_value()) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
if (argument_tokens.next_token().is(Token::Type::Comma)) {
|
||||
argument_tokens.discard_a_token();
|
||||
argument_tokens.discard_whitespace();
|
||||
fallback_value = parse_length_percentage_value(argument_tokens);
|
||||
if (!fallback_value) {
|
||||
fallback_value = parse_anchor(argument_tokens);
|
||||
if (!fallback_value)
|
||||
return {};
|
||||
argument_tokens.discard_a_token();
|
||||
}
|
||||
}
|
||||
|
||||
if (argument_tokens.has_next_token())
|
||||
return {};
|
||||
|
||||
if (!anchor_side_value)
|
||||
return {};
|
||||
|
||||
return AnchorStyleValue::create(anchor_name, anchor_side_value.release_nonnull(), fallback_value);
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/css-anchor-position-1/#sizing
|
||||
RefPtr<CSSStyleValue const> Parser::parse_anchor_size(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
|
@ -4507,6 +4577,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::Anchor:
|
||||
return parse_anchor(tokens);
|
||||
case ValueType::AnchorSize:
|
||||
return parse_anchor_size(tokens);
|
||||
case ValueType::Angle:
|
||||
|
|
|
@ -1123,7 +1123,8 @@
|
|||
"initial": "auto",
|
||||
"valid-types": [
|
||||
"length [-∞,∞]",
|
||||
"percentage [-∞,∞]"
|
||||
"percentage [-∞,∞]",
|
||||
"anchor"
|
||||
],
|
||||
"valid-identifiers": [
|
||||
"auto"
|
||||
|
@ -2151,7 +2152,8 @@
|
|||
"initial": "auto",
|
||||
"valid-types": [
|
||||
"length [-∞,∞]",
|
||||
"percentage [-∞,∞]"
|
||||
"percentage [-∞,∞]",
|
||||
"anchor"
|
||||
],
|
||||
"valid-identifiers": [
|
||||
"auto"
|
||||
|
@ -2862,7 +2864,8 @@
|
|||
"initial": "auto",
|
||||
"valid-types": [
|
||||
"length [-∞,∞]",
|
||||
"percentage [-∞,∞]"
|
||||
"percentage [-∞,∞]",
|
||||
"anchor"
|
||||
],
|
||||
"valid-identifiers": [
|
||||
"auto"
|
||||
|
@ -3234,7 +3237,8 @@
|
|||
"initial": "auto",
|
||||
"valid-types": [
|
||||
"length [-∞,∞]",
|
||||
"percentage [-∞,∞]"
|
||||
"percentage [-∞,∞]",
|
||||
"anchor"
|
||||
],
|
||||
"valid-identifiers": [
|
||||
"auto"
|
||||
|
|
48
Libraries/LibWeb/CSS/StyleValues/AnchorStyleValue.cpp
Normal file
48
Libraries/LibWeb/CSS/StyleValues/AnchorStyleValue.cpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Tim Ledbetter <tim.ledbetter@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/CSS/StyleValues/AnchorStyleValue.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
ValueComparingNonnullRefPtr<AnchorStyleValue const> AnchorStyleValue::create(
|
||||
Optional<FlyString> const& anchor_name,
|
||||
ValueComparingNonnullRefPtr<CSSStyleValue const> const& anchor_side,
|
||||
ValueComparingRefPtr<CSSStyleValue const> const& fallback_value)
|
||||
{
|
||||
return adopt_ref(*new (nothrow) AnchorStyleValue(anchor_name, anchor_side, fallback_value));
|
||||
}
|
||||
|
||||
AnchorStyleValue::AnchorStyleValue(Optional<FlyString> const& anchor_name,
|
||||
ValueComparingNonnullRefPtr<CSSStyleValue const> const& anchor_side,
|
||||
ValueComparingRefPtr<CSSStyleValue const> const& fallback_value)
|
||||
: StyleValueWithDefaultOperators(Type::Anchor)
|
||||
, m_properties { .anchor_name = anchor_name, .anchor_side = anchor_side, .fallback_value = fallback_value }
|
||||
{
|
||||
}
|
||||
|
||||
String AnchorStyleValue::to_string(SerializationMode serialization_mode) const
|
||||
{
|
||||
StringBuilder builder;
|
||||
builder.append("anchor("sv);
|
||||
|
||||
if (anchor_name().has_value())
|
||||
builder.append(anchor_name().value());
|
||||
|
||||
if (anchor_name().has_value())
|
||||
builder.append(' ');
|
||||
builder.append(anchor_side()->to_string(serialization_mode));
|
||||
|
||||
if (fallback_value()) {
|
||||
builder.append(", "sv);
|
||||
builder.append(fallback_value()->to_string(serialization_mode));
|
||||
}
|
||||
|
||||
builder.append(')');
|
||||
return MUST(builder.to_string());
|
||||
}
|
||||
|
||||
}
|
48
Libraries/LibWeb/CSS/StyleValues/AnchorStyleValue.h
Normal file
48
Libraries/LibWeb/CSS/StyleValues/AnchorStyleValue.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Tim Ledbetter <tim.ledbetter@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 AnchorStyleValue final : public StyleValueWithDefaultOperators<AnchorStyleValue> {
|
||||
public:
|
||||
static ValueComparingNonnullRefPtr<AnchorStyleValue const> create(Optional<FlyString> const& anchor_name,
|
||||
ValueComparingNonnullRefPtr<CSSStyleValue const> const& anchor_side,
|
||||
ValueComparingRefPtr<CSSStyleValue const> const& fallback_value);
|
||||
virtual ~AnchorStyleValue() override = default;
|
||||
|
||||
virtual String to_string(SerializationMode) const override;
|
||||
|
||||
bool properties_equal(AnchorStyleValue const& other) const { return m_properties == other.m_properties; }
|
||||
|
||||
Optional<FlyString const&> anchor_name() const { return m_properties.anchor_name; }
|
||||
ValueComparingNonnullRefPtr<CSSStyleValue const> anchor_side() const
|
||||
{
|
||||
return m_properties.anchor_side;
|
||||
}
|
||||
ValueComparingRefPtr<CSSStyleValue const> fallback_value() const
|
||||
{
|
||||
return m_properties.fallback_value;
|
||||
}
|
||||
|
||||
private:
|
||||
AnchorStyleValue(Optional<FlyString> const& anchor_name, ValueComparingNonnullRefPtr<CSSStyleValue const> const& anchor_side, ValueComparingRefPtr<CSSStyleValue const> const& fallback_value);
|
||||
|
||||
struct Properties {
|
||||
Optional<FlyString> anchor_name;
|
||||
ValueComparingNonnullRefPtr<CSSStyleValue const> anchor_side;
|
||||
ValueComparingRefPtr<CSSStyleValue const> fallback_value;
|
||||
bool operator==(Properties const&) const = default;
|
||||
} m_properties;
|
||||
};
|
||||
|
||||
}
|
|
@ -12,6 +12,7 @@
|
|||
namespace Web::CSS {
|
||||
|
||||
enum class ValueType : u8 {
|
||||
Anchor,
|
||||
AnchorSize,
|
||||
Angle,
|
||||
BackgroundPosition,
|
||||
|
|
|
@ -192,6 +192,7 @@ class SubtleCrypto;
|
|||
namespace Web::CSS {
|
||||
|
||||
class AbstractImageStyleValue;
|
||||
class AnchorStyleValue;
|
||||
class AnchorSizeStyleValue;
|
||||
class Angle;
|
||||
class AngleOrCalculated;
|
||||
|
|
|
@ -830,7 +830,9 @@ bool property_accepts_type(PropertyID property_id, ValueType value_type)
|
|||
if (enum_names.contains_slow(type_name))
|
||||
continue;
|
||||
|
||||
if (type_name == "angle") {
|
||||
if (type_name == "anchor") {
|
||||
property_generator.appendln(" case ValueType::Anchor:");
|
||||
} else if (type_name == "angle") {
|
||||
property_generator.appendln(" case ValueType::Angle:");
|
||||
} else if (type_name == "background-position") {
|
||||
property_generator.appendln(" case ValueType::BackgroundPosition:");
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 24 tests
|
||||
|
||||
24 Pass
|
||||
Pass e.style['margin-top'] = "anchor(--foo top)" should not set the property value
|
||||
Pass e.style['height'] = "anchor(--foo top)" should not set the property value
|
||||
Pass e.style['font-size'] = "anchor(--foo top)" should not set the property value
|
||||
Pass e.style['top'] = "anchor(--foo, top)" should not set the property value
|
||||
Pass e.style['top'] = "anchor(--foo top,)" should not set the property value
|
||||
Pass e.style['top'] = "anchor(--foo top bottom)" should not set the property value
|
||||
Pass e.style['top'] = "anchor(--foo top, 10px 20%)" should not set the property value
|
||||
Pass e.style['top'] = "anchor(--foo top, 10px, 20%)" should not set the property value
|
||||
Pass e.style['top'] = "anchor(2 * 20%)" should not set the property value
|
||||
Pass e.style['top'] = "anchor((2 * 20%))" should not set the property value
|
||||
Pass e.style['top'] = "anchor(foo top)" should not set the property value
|
||||
Pass e.style['top'] = "anchor(top foo)" should not set the property value
|
||||
Pass e.style['top'] = "anchor(--foo height)" should not set the property value
|
||||
Pass e.style['top'] = "anchor(--foo 10em)" should not set the property value
|
||||
Pass e.style['top'] = "anchor(--foo 100s)" should not set the property value
|
||||
Pass e.style['top'] = "anchor(--foo top, 1)" should not set the property value
|
||||
Pass e.style['top'] = "anchor(--foo top, 100s)" should not set the property value
|
||||
Pass e.style['top'] = "anchor(--foo top, bottom)" should not set the property value
|
||||
Pass e.style['top'] = "anchor(--foo top, anchor(bar top))" should not set the property value
|
||||
Pass e.style['top'] = "anchor(--foo top, anchor-size(bar height))" should not set the property value
|
||||
Pass e.style['top'] = "anchor(--foo top, auto" should not set the property value
|
||||
Pass e.style['top'] = "calc(anchor(foo top) + 10px + 10%)" should not set the property value
|
||||
Pass e.style['top'] = "calc(10px + 100 * anchor(--foo top, anchor(bar bottom)))" should not set the property value
|
||||
Pass e.style['top'] = "min(anchor(--foo top), anchor(--bar bottom), anchor-size(baz height))" should not set the property value
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,45 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Tests values that are invalid at parse time for the anchor() function</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
|
||||
<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() can only be used in inset properties
|
||||
test_invalid_value('margin-top', 'anchor(--foo top)');
|
||||
test_invalid_value('height', 'anchor(--foo top)');
|
||||
test_invalid_value('font-size', 'anchor(--foo top)');
|
||||
|
||||
// Invalid parameter format
|
||||
test_invalid_value('top', 'anchor(--foo, top)');
|
||||
test_invalid_value('top', 'anchor(--foo top,)');
|
||||
test_invalid_value('top', 'anchor(--foo top bottom)');
|
||||
test_invalid_value('top', 'anchor(--foo top, 10px 20%)');
|
||||
test_invalid_value('top', 'anchor(--foo top, 10px, 20%)');
|
||||
test_invalid_value('top', 'anchor(2 * 20%)');
|
||||
test_invalid_value('top', 'anchor((2 * 20%))');
|
||||
|
||||
// Anchor name must be a dashed ident
|
||||
test_invalid_value('top', 'anchor(foo top)');
|
||||
test_invalid_value('top', 'anchor(top foo)');
|
||||
|
||||
// Invalid anchor side values
|
||||
test_invalid_value('top', 'anchor(--foo height)');
|
||||
test_invalid_value('top', 'anchor(--foo 10em)');
|
||||
test_invalid_value('top', 'anchor(--foo 100s)');
|
||||
|
||||
// Invalid fallback values
|
||||
test_invalid_value('top', 'anchor(--foo top, 1)');
|
||||
test_invalid_value('top', 'anchor(--foo top, 100s)');
|
||||
test_invalid_value('top', 'anchor(--foo top, bottom)');
|
||||
test_invalid_value('top', 'anchor(--foo top, anchor(bar top))');
|
||||
test_invalid_value('top', 'anchor(--foo top, anchor-size(bar height))');
|
||||
test_invalid_value('top', 'anchor(--foo top, auto');
|
||||
|
||||
// Invalid anchor values in calc tree
|
||||
test_invalid_value('top', 'calc(anchor(foo top) + 10px + 10%)');
|
||||
test_invalid_value('top', 'calc(10px + 100 * anchor(--foo top, anchor(bar bottom)))');
|
||||
test_invalid_value('top', 'min(anchor(--foo top), anchor(--bar bottom), anchor-size(baz height))');
|
||||
</script>
|
|
@ -0,0 +1,78 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Tests parsing of the anchor() function</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
|
||||
<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>
|
||||
const anchorNames = [
|
||||
'',
|
||||
'--foo',
|
||||
];
|
||||
|
||||
const insetProperties = [
|
||||
'left',
|
||||
'right',
|
||||
'top',
|
||||
'bottom',
|
||||
'inset-block-start',
|
||||
'inset-block-end',
|
||||
'inset-inline-start',
|
||||
'inset-inline-end',
|
||||
];
|
||||
|
||||
const anchorSides = [
|
||||
'inside',
|
||||
'outside',
|
||||
'left',
|
||||
'right',
|
||||
'top',
|
||||
'bottom',
|
||||
'start',
|
||||
'end',
|
||||
'self-start',
|
||||
'self-end',
|
||||
'center',
|
||||
'50%',
|
||||
'calc(50%)',
|
||||
'min(50%, 100%)',
|
||||
];
|
||||
|
||||
const fallbacks = [
|
||||
null,
|
||||
'1px',
|
||||
'50%',
|
||||
'calc(50% + 1px)',
|
||||
'anchor(left)',
|
||||
'anchor(--bar left)',
|
||||
'anchor(--bar left, anchor(--baz right))',
|
||||
];
|
||||
|
||||
// Tests basic combinations
|
||||
for (let property of insetProperties) {
|
||||
// Using a wrong anchor-side (e.g., `top: anchor(--foo left)`) doesn't cause a
|
||||
// parse error, but triggers the fallback when resolved.
|
||||
for (let name of anchorNames) {
|
||||
for (let side of anchorSides) {
|
||||
for (let fallback of fallbacks) {
|
||||
let value = `anchor(${name ? name + ' ' : ''}${side}${fallback ? ', ' + fallback : ''})`;
|
||||
test_valid_value(property, value);
|
||||
if (name) {
|
||||
// The <anchor-element> is allowed to appear after the <anchor-side>
|
||||
let value_flip_order = `anchor(${side} ${name}${fallback ? ', ' + fallback : ''})`;
|
||||
test_valid_value(property, value_flip_order, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that anchor() can be used in a calc tree
|
||||
// Still follow the simplification process as outlined in https://drafts.csswg.org/css-values-4/#calc-simplification
|
||||
test_valid_value('top', 'calc((anchor(--foo top) + anchor(--bar bottom)) / 2)', 'calc(0.5 * (anchor(--foo top) + anchor(--bar bottom)))');
|
||||
test_valid_value('top', 'calc(0.5 * (anchor(--foo top) + anchor(--bar bottom)))');
|
||||
test_valid_value('top', 'anchor(--foo top, calc(0.5 * anchor(--bar bottom)))');
|
||||
test_valid_value('top', 'min(100px, 10%, anchor(--foo top), anchor(--bar bottom))');
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue