mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-22 17:29:01 +00:00
LibWeb/CSS: Reify math functions into CSSMathValue types
This commit is contained in:
parent
9264f540dd
commit
d29084997e
Notes:
github-actions[bot]
2025-08-29 09:58:30 +00:00
Author: https://github.com/AtkinsSJ
Commit: d29084997e
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5955
Reviewed-by: https://github.com/trflynn89
5 changed files with 121 additions and 11 deletions
|
@ -10,6 +10,16 @@
|
||||||
#include "CalculatedStyleValue.h"
|
#include "CalculatedStyleValue.h"
|
||||||
#include <AK/QuickSort.h>
|
#include <AK/QuickSort.h>
|
||||||
#include <AK/TypeCasts.h>
|
#include <AK/TypeCasts.h>
|
||||||
|
#include <LibJS/Runtime/Realm.h>
|
||||||
|
#include <LibWeb/CSS/CSSMathClamp.h>
|
||||||
|
#include <LibWeb/CSS/CSSMathInvert.h>
|
||||||
|
#include <LibWeb/CSS/CSSMathMax.h>
|
||||||
|
#include <LibWeb/CSS/CSSMathMin.h>
|
||||||
|
#include <LibWeb/CSS/CSSMathNegate.h>
|
||||||
|
#include <LibWeb/CSS/CSSMathProduct.h>
|
||||||
|
#include <LibWeb/CSS/CSSMathSum.h>
|
||||||
|
#include <LibWeb/CSS/CSSNumericArray.h>
|
||||||
|
#include <LibWeb/CSS/CSSUnitValue.h>
|
||||||
#include <LibWeb/CSS/Percentage.h>
|
#include <LibWeb/CSS/Percentage.h>
|
||||||
#include <LibWeb/CSS/PropertyID.h>
|
#include <LibWeb/CSS/PropertyID.h>
|
||||||
#include <LibWeb/CSS/StyleValues/AngleStyleValue.h>
|
#include <LibWeb/CSS/StyleValues/AngleStyleValue.h>
|
||||||
|
@ -190,6 +200,18 @@ static CalculationNode::NumericValue clamp_and_censor_numeric_value(NumericCalcu
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GC::Ptr<CSSNumericArray> reify_children(JS::Realm& realm, ReadonlySpan<NonnullRefPtr<CalculationNode const>> children)
|
||||||
|
{
|
||||||
|
GC::RootVector<GC::Ref<CSSNumericValue>> reified_children { realm.heap() };
|
||||||
|
for (auto const& child : children) {
|
||||||
|
auto reified_child = child->reify(realm);
|
||||||
|
if (!reified_child)
|
||||||
|
return nullptr;
|
||||||
|
reified_children.append(reified_child.as_nonnull());
|
||||||
|
}
|
||||||
|
return CSSNumericArray::create(realm, move(reified_children));
|
||||||
|
}
|
||||||
|
|
||||||
static String serialize_a_calculation_tree(CalculationNode const&, CalculationContext const&, SerializationMode);
|
static String serialize_a_calculation_tree(CalculationNode const&, CalculationContext const&, SerializationMode);
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-values-4/#serialize-a-math-function
|
// https://drafts.csswg.org/css-values-4/#serialize-a-math-function
|
||||||
|
@ -803,6 +825,14 @@ bool NumericCalculationNode::equals(CalculationNode const& other) const
|
||||||
return m_value == static_cast<NumericCalculationNode const&>(other).m_value;
|
return m_value == static_cast<NumericCalculationNode const&>(other).m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GC::Ptr<CSSNumericValue> NumericCalculationNode::reify(JS::Realm& realm) const
|
||||||
|
{
|
||||||
|
return m_value.visit(
|
||||||
|
[&realm](Number const& number) { return CSSUnitValue::create(realm, number.value(), "number"_fly_string); },
|
||||||
|
[&realm](Percentage const& percentage) { return CSSUnitValue::create(realm, percentage.value(), "percent"_fly_string); },
|
||||||
|
[&realm](auto const& dimension) { return CSSUnitValue::create(realm, dimension.raw_value(), FlyString::from_utf8_without_validation(dimension.unit_name().bytes())); });
|
||||||
|
}
|
||||||
|
|
||||||
NonnullRefPtr<SumCalculationNode const> SumCalculationNode::create(Vector<NonnullRefPtr<CalculationNode const>> values)
|
NonnullRefPtr<SumCalculationNode const> SumCalculationNode::create(Vector<NonnullRefPtr<CalculationNode const>> values)
|
||||||
{
|
{
|
||||||
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
|
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
|
||||||
|
@ -874,6 +904,14 @@ bool SumCalculationNode::equals(CalculationNode const& other) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GC::Ptr<CSSNumericValue> SumCalculationNode::reify(JS::Realm& realm) const
|
||||||
|
{
|
||||||
|
auto reified_children = reify_children(realm, m_values);
|
||||||
|
if (!reified_children)
|
||||||
|
return nullptr;
|
||||||
|
return CSSMathSum::create(realm, numeric_type().value(), reified_children.as_nonnull());
|
||||||
|
}
|
||||||
|
|
||||||
NonnullRefPtr<ProductCalculationNode const> ProductCalculationNode::create(Vector<NonnullRefPtr<CalculationNode const>> values)
|
NonnullRefPtr<ProductCalculationNode const> ProductCalculationNode::create(Vector<NonnullRefPtr<CalculationNode const>> values)
|
||||||
{
|
{
|
||||||
// https://drafts.csswg.org/css-values-4/#determine-the-type-of-a-calculation
|
// https://drafts.csswg.org/css-values-4/#determine-the-type-of-a-calculation
|
||||||
|
@ -944,6 +982,14 @@ bool ProductCalculationNode::equals(CalculationNode const& other) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GC::Ptr<CSSNumericValue> ProductCalculationNode::reify(JS::Realm& realm) const
|
||||||
|
{
|
||||||
|
auto reified_children = reify_children(realm, m_values);
|
||||||
|
if (!reified_children)
|
||||||
|
return nullptr;
|
||||||
|
return CSSMathProduct::create(realm, numeric_type().value(), reified_children.as_nonnull());
|
||||||
|
}
|
||||||
|
|
||||||
NonnullRefPtr<NegateCalculationNode const> NegateCalculationNode::create(NonnullRefPtr<CalculationNode const> value)
|
NonnullRefPtr<NegateCalculationNode const> NegateCalculationNode::create(NonnullRefPtr<CalculationNode const> value)
|
||||||
{
|
{
|
||||||
return adopt_ref(*new (nothrow) NegateCalculationNode(move(value)));
|
return adopt_ref(*new (nothrow) NegateCalculationNode(move(value)));
|
||||||
|
@ -990,6 +1036,14 @@ bool NegateCalculationNode::equals(CalculationNode const& other) const
|
||||||
return m_value->equals(*static_cast<NegateCalculationNode const&>(other).m_value);
|
return m_value->equals(*static_cast<NegateCalculationNode const&>(other).m_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GC::Ptr<CSSNumericValue> NegateCalculationNode::reify(JS::Realm& realm) const
|
||||||
|
{
|
||||||
|
auto reified_value = m_value->reify(realm);
|
||||||
|
if (!reified_value)
|
||||||
|
return nullptr;
|
||||||
|
return CSSMathNegate::create(realm, numeric_type().value(), reified_value.as_nonnull());
|
||||||
|
}
|
||||||
|
|
||||||
NonnullRefPtr<InvertCalculationNode const> InvertCalculationNode::create(NonnullRefPtr<CalculationNode const> value)
|
NonnullRefPtr<InvertCalculationNode const> InvertCalculationNode::create(NonnullRefPtr<CalculationNode const> value)
|
||||||
{
|
{
|
||||||
// https://drafts.csswg.org/css-values-4/#determine-the-type-of-a-calculation
|
// https://drafts.csswg.org/css-values-4/#determine-the-type-of-a-calculation
|
||||||
|
@ -1042,6 +1096,14 @@ bool InvertCalculationNode::equals(CalculationNode const& other) const
|
||||||
return m_value->equals(*static_cast<InvertCalculationNode const&>(other).m_value);
|
return m_value->equals(*static_cast<InvertCalculationNode const&>(other).m_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GC::Ptr<CSSNumericValue> InvertCalculationNode::reify(JS::Realm& realm) const
|
||||||
|
{
|
||||||
|
auto reified_value = m_value->reify(realm);
|
||||||
|
if (!reified_value)
|
||||||
|
return nullptr;
|
||||||
|
return CSSMathInvert::create(realm, numeric_type().value(), reified_value.as_nonnull());
|
||||||
|
}
|
||||||
|
|
||||||
NonnullRefPtr<MinCalculationNode const> MinCalculationNode::create(Vector<NonnullRefPtr<CalculationNode const>> values)
|
NonnullRefPtr<MinCalculationNode const> MinCalculationNode::create(Vector<NonnullRefPtr<CalculationNode const>> values)
|
||||||
{
|
{
|
||||||
// https://drafts.csswg.org/css-values-4/#determine-the-type-of-a-calculation
|
// https://drafts.csswg.org/css-values-4/#determine-the-type-of-a-calculation
|
||||||
|
@ -1166,6 +1228,14 @@ bool MinCalculationNode::equals(CalculationNode const& other) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GC::Ptr<CSSNumericValue> MinCalculationNode::reify(JS::Realm& realm) const
|
||||||
|
{
|
||||||
|
auto reified_children = reify_children(realm, m_values);
|
||||||
|
if (!reified_children)
|
||||||
|
return nullptr;
|
||||||
|
return CSSMathMin::create(realm, numeric_type().value(), reified_children.as_nonnull());
|
||||||
|
}
|
||||||
|
|
||||||
NonnullRefPtr<MaxCalculationNode const> MaxCalculationNode::create(Vector<NonnullRefPtr<CalculationNode const>> values)
|
NonnullRefPtr<MaxCalculationNode const> MaxCalculationNode::create(Vector<NonnullRefPtr<CalculationNode const>> values)
|
||||||
{
|
{
|
||||||
// https://drafts.csswg.org/css-values-4/#determine-the-type-of-a-calculation
|
// https://drafts.csswg.org/css-values-4/#determine-the-type-of-a-calculation
|
||||||
|
@ -1243,6 +1313,14 @@ bool MaxCalculationNode::equals(CalculationNode const& other) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GC::Ptr<CSSNumericValue> MaxCalculationNode::reify(JS::Realm& realm) const
|
||||||
|
{
|
||||||
|
auto reified_children = reify_children(realm, m_values);
|
||||||
|
if (!reified_children)
|
||||||
|
return nullptr;
|
||||||
|
return CSSMathMax::create(realm, numeric_type().value(), reified_children.as_nonnull());
|
||||||
|
}
|
||||||
|
|
||||||
NonnullRefPtr<ClampCalculationNode const> ClampCalculationNode::create(NonnullRefPtr<CalculationNode const> min, NonnullRefPtr<CalculationNode const> center, NonnullRefPtr<CalculationNode const> max)
|
NonnullRefPtr<ClampCalculationNode const> ClampCalculationNode::create(NonnullRefPtr<CalculationNode const> min, NonnullRefPtr<CalculationNode const> center, NonnullRefPtr<CalculationNode const> max)
|
||||||
{
|
{
|
||||||
// https://drafts.csswg.org/css-values-4/#determine-the-type-of-a-calculation
|
// https://drafts.csswg.org/css-values-4/#determine-the-type-of-a-calculation
|
||||||
|
@ -1358,6 +1436,17 @@ bool ClampCalculationNode::equals(CalculationNode const& other) const
|
||||||
&& m_max_value->equals(*static_cast<ClampCalculationNode const&>(other).m_max_value);
|
&& m_max_value->equals(*static_cast<ClampCalculationNode const&>(other).m_max_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GC::Ptr<CSSNumericValue> ClampCalculationNode::reify(JS::Realm& realm) const
|
||||||
|
{
|
||||||
|
auto lower = m_min_value->reify(realm);
|
||||||
|
auto value = m_center_value->reify(realm);
|
||||||
|
auto upper = m_max_value->reify(realm);
|
||||||
|
if (!lower || !value || !upper)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return CSSMathClamp::create(realm, numeric_type().value(), lower.as_nonnull(), value.as_nonnull(), upper.as_nonnull());
|
||||||
|
}
|
||||||
|
|
||||||
NonnullRefPtr<AbsCalculationNode const> AbsCalculationNode::create(NonnullRefPtr<CalculationNode const> value)
|
NonnullRefPtr<AbsCalculationNode const> AbsCalculationNode::create(NonnullRefPtr<CalculationNode const> value)
|
||||||
{
|
{
|
||||||
return adopt_ref(*new (nothrow) AbsCalculationNode(move(value)));
|
return adopt_ref(*new (nothrow) AbsCalculationNode(move(value)));
|
||||||
|
@ -3037,6 +3126,18 @@ String CalculatedStyleValue::dump() const
|
||||||
return builder.to_string_without_validation();
|
return builder.to_string_without_validation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://drafts.css-houdini.org/css-typed-om-1/#reify-a-math-expression
|
||||||
|
GC::Ref<CSSStyleValue> CalculatedStyleValue::reify(JS::Realm& realm, String const& associated_property) const
|
||||||
|
{
|
||||||
|
// NB: This spec algorithm isn't really implementable here - it's incomplete, and assumes we don't already have a
|
||||||
|
// calculation tree. So we have a per-node method instead.
|
||||||
|
if (auto reified = m_calculation->reify(realm))
|
||||||
|
return *reified;
|
||||||
|
// Some math functions are not reifiable yet. If we contain one, we have to fall back to CSSStyleValue.
|
||||||
|
// https://github.com/w3c/css-houdini-drafts/issues/1090
|
||||||
|
return StyleValue::reify(realm, associated_property);
|
||||||
|
}
|
||||||
|
|
||||||
struct NumericChildAndIndex {
|
struct NumericChildAndIndex {
|
||||||
NonnullRefPtr<NumericCalculationNode const> child;
|
NonnullRefPtr<NumericCalculationNode const> child;
|
||||||
size_t index;
|
size_t index;
|
||||||
|
|
|
@ -117,6 +117,8 @@ public:
|
||||||
|
|
||||||
String dump() const;
|
String dump() const;
|
||||||
|
|
||||||
|
virtual GC::Ref<CSSStyleValue> reify(JS::Realm&, String const& associated_property) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit CalculatedStyleValue(NonnullRefPtr<CalculationNode const> calculation, NumericType resolved_type, CalculationContext context)
|
explicit CalculatedStyleValue(NonnullRefPtr<CalculationNode const> calculation, NumericType resolved_type, CalculationContext context)
|
||||||
: StyleValue(Type::Calculated)
|
: StyleValue(Type::Calculated)
|
||||||
|
@ -249,6 +251,7 @@ public:
|
||||||
|
|
||||||
virtual void dump(StringBuilder&, int indent) const = 0;
|
virtual void dump(StringBuilder&, int indent) const = 0;
|
||||||
virtual bool equals(CalculationNode const&) const = 0;
|
virtual bool equals(CalculationNode const&) const = 0;
|
||||||
|
virtual GC::Ptr<CSSNumericValue> reify(JS::Realm&) const { return nullptr; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
CalculationNode(Type, Optional<NumericType>);
|
CalculationNode(Type, Optional<NumericType>);
|
||||||
|
@ -287,6 +290,7 @@ public:
|
||||||
|
|
||||||
virtual void dump(StringBuilder&, int indent) const override;
|
virtual void dump(StringBuilder&, int indent) const override;
|
||||||
virtual bool equals(CalculationNode const&) const override;
|
virtual bool equals(CalculationNode const&) const override;
|
||||||
|
virtual GC::Ptr<CSSNumericValue> reify(JS::Realm&) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NumericCalculationNode(NumericValue, NumericType);
|
NumericCalculationNode(NumericValue, NumericType);
|
||||||
|
@ -306,6 +310,7 @@ public:
|
||||||
|
|
||||||
virtual void dump(StringBuilder&, int indent) const override;
|
virtual void dump(StringBuilder&, int indent) const override;
|
||||||
virtual bool equals(CalculationNode const&) const override;
|
virtual bool equals(CalculationNode const&) const override;
|
||||||
|
virtual GC::Ptr<CSSNumericValue> reify(JS::Realm&) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SumCalculationNode(Vector<NonnullRefPtr<CalculationNode const>>, Optional<NumericType>);
|
SumCalculationNode(Vector<NonnullRefPtr<CalculationNode const>>, Optional<NumericType>);
|
||||||
|
@ -325,6 +330,7 @@ public:
|
||||||
|
|
||||||
virtual void dump(StringBuilder&, int indent) const override;
|
virtual void dump(StringBuilder&, int indent) const override;
|
||||||
virtual bool equals(CalculationNode const&) const override;
|
virtual bool equals(CalculationNode const&) const override;
|
||||||
|
virtual GC::Ptr<CSSNumericValue> reify(JS::Realm&) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ProductCalculationNode(Vector<NonnullRefPtr<CalculationNode const>>, Optional<NumericType>);
|
ProductCalculationNode(Vector<NonnullRefPtr<CalculationNode const>>, Optional<NumericType>);
|
||||||
|
@ -345,6 +351,7 @@ public:
|
||||||
|
|
||||||
virtual void dump(StringBuilder&, int indent) const override;
|
virtual void dump(StringBuilder&, int indent) const override;
|
||||||
virtual bool equals(CalculationNode const&) const override;
|
virtual bool equals(CalculationNode const&) const override;
|
||||||
|
virtual GC::Ptr<CSSNumericValue> reify(JS::Realm&) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit NegateCalculationNode(NonnullRefPtr<CalculationNode const>);
|
explicit NegateCalculationNode(NonnullRefPtr<CalculationNode const>);
|
||||||
|
@ -365,6 +372,7 @@ public:
|
||||||
|
|
||||||
virtual void dump(StringBuilder&, int indent) const override;
|
virtual void dump(StringBuilder&, int indent) const override;
|
||||||
virtual bool equals(CalculationNode const&) const override;
|
virtual bool equals(CalculationNode const&) const override;
|
||||||
|
virtual GC::Ptr<CSSNumericValue> reify(JS::Realm&) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
InvertCalculationNode(NonnullRefPtr<CalculationNode const>, Optional<NumericType>);
|
InvertCalculationNode(NonnullRefPtr<CalculationNode const>, Optional<NumericType>);
|
||||||
|
@ -385,6 +393,7 @@ public:
|
||||||
|
|
||||||
virtual void dump(StringBuilder&, int indent) const override;
|
virtual void dump(StringBuilder&, int indent) const override;
|
||||||
virtual bool equals(CalculationNode const&) const override;
|
virtual bool equals(CalculationNode const&) const override;
|
||||||
|
virtual GC::Ptr<CSSNumericValue> reify(JS::Realm&) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MinCalculationNode(Vector<NonnullRefPtr<CalculationNode const>>, Optional<NumericType>);
|
MinCalculationNode(Vector<NonnullRefPtr<CalculationNode const>>, Optional<NumericType>);
|
||||||
|
@ -405,6 +414,7 @@ public:
|
||||||
|
|
||||||
virtual void dump(StringBuilder&, int indent) const override;
|
virtual void dump(StringBuilder&, int indent) const override;
|
||||||
virtual bool equals(CalculationNode const&) const override;
|
virtual bool equals(CalculationNode const&) const override;
|
||||||
|
virtual GC::Ptr<CSSNumericValue> reify(JS::Realm&) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MaxCalculationNode(Vector<NonnullRefPtr<CalculationNode const>>, Optional<NumericType>);
|
MaxCalculationNode(Vector<NonnullRefPtr<CalculationNode const>>, Optional<NumericType>);
|
||||||
|
@ -425,6 +435,7 @@ public:
|
||||||
|
|
||||||
virtual void dump(StringBuilder&, int indent) const override;
|
virtual void dump(StringBuilder&, int indent) const override;
|
||||||
virtual bool equals(CalculationNode const&) const override;
|
virtual bool equals(CalculationNode const&) const override;
|
||||||
|
virtual GC::Ptr<CSSNumericValue> reify(JS::Realm&) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ClampCalculationNode(NonnullRefPtr<CalculationNode const>, NonnullRefPtr<CalculationNode const>, NonnullRefPtr<CalculationNode const>, Optional<NumericType>);
|
ClampCalculationNode(NonnullRefPtr<CalculationNode const>, NonnullRefPtr<CalculationNode const>, NonnullRefPtr<CalculationNode const>, Optional<NumericType>);
|
||||||
|
|
|
@ -2,6 +2,6 @@ Harness status: OK
|
||||||
|
|
||||||
Found 2 tests
|
Found 2 tests
|
||||||
|
|
||||||
2 Fail
|
2 Pass
|
||||||
Fail Parsing calc(1% + 2em + 3px)
|
Pass Parsing calc(1% + 2em + 3px)
|
||||||
Fail Parsing calc(1px + 2% + 3em)
|
Pass Parsing calc(1px + 2% + 3em)
|
|
@ -2,11 +2,10 @@ Harness status: OK
|
||||||
|
|
||||||
Found 6 tests
|
Found 6 tests
|
||||||
|
|
||||||
5 Pass
|
6 Pass
|
||||||
1 Fail
|
|
||||||
Pass Normalizing a <number> returns a number CSSUnitValue
|
Pass Normalizing a <number> returns a number CSSUnitValue
|
||||||
Pass Normalizing a <percentage> returns a percent CSSUnitValue
|
Pass Normalizing a <percentage> returns a percent CSSUnitValue
|
||||||
Pass Normalizing a <dimension> returns a CSSUnitValue with the correct unit
|
Pass Normalizing a <dimension> returns a CSSUnitValue with the correct unit
|
||||||
Pass Normalizing a <number> with a unitless zero returns 0
|
Pass Normalizing a <number> with a unitless zero returns 0
|
||||||
Fail Normalizing a <calc> returns simplified expression
|
Pass Normalizing a <calc> returns simplified expression
|
||||||
Pass Normalizing a <dimension> with a unitless zero returns 0px
|
Pass Normalizing a <dimension> with a unitless zero returns 0px
|
|
@ -2,16 +2,15 @@ Harness status: OK
|
||||||
|
|
||||||
Found 11 tests
|
Found 11 tests
|
||||||
|
|
||||||
8 Pass
|
11 Pass
|
||||||
3 Fail
|
|
||||||
Pass Parsing an invalid string throws SyntaxError
|
Pass Parsing an invalid string throws SyntaxError
|
||||||
Pass Parsing a string with a non numeric token throws SyntaxError
|
Pass Parsing a string with a non numeric token throws SyntaxError
|
||||||
Pass Parsing a string with left over numeric tokens throws SyntaxError
|
Pass Parsing a string with left over numeric tokens throws SyntaxError
|
||||||
Pass Parsing a calc with incompatible units throws a SyntaxError
|
Pass Parsing a calc with incompatible units throws a SyntaxError
|
||||||
Pass Parsing a <dimension-token> with invalid units throws a SyntaxError
|
Pass Parsing a <dimension-token> with invalid units throws a SyntaxError
|
||||||
Pass Parsing ignores surrounding spaces
|
Pass Parsing ignores surrounding spaces
|
||||||
Fail Parsing min() is successful
|
Pass Parsing min() is successful
|
||||||
Fail Parsing max() is successful
|
Pass Parsing max() is successful
|
||||||
Fail Parsing clamp() is successful
|
Pass Parsing clamp() is successful
|
||||||
Pass Parsing sum of multiple min() is successful
|
Pass Parsing sum of multiple min() is successful
|
||||||
Pass Parsing product of multiple min() is successful
|
Pass Parsing product of multiple min() is successful
|
Loading…
Add table
Add a link
Reference in a new issue