2023-03-30 17:34:14 +01:00
/*
* Copyright ( c ) 2018 - 2020 , Andreas Kling < kling @ serenityos . org >
* Copyright ( c ) 2021 , Tobias Christiansen < tobyase @ serenityos . org >
* Copyright ( c ) 2021 - 2023 , Sam Atkins < atkinssj @ serenityos . org >
* Copyright ( c ) 2022 - 2023 , MacDue < macdue @ dueutil . tech >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include "CalculatedStyleValue.h"
# include <LibWeb/CSS/Percentage.h>
2023-07-05 19:58:13 +01:00
# include <LibWeb/CSS/PropertyID.h>
2023-03-30 17:34:14 +01:00
namespace Web : : CSS {
2023-04-11 15:48:06 +01:00
static bool is_number ( CalculatedStyleValue : : ResolvedType type )
{
return type = = CalculatedStyleValue : : ResolvedType : : Number | | type = = CalculatedStyleValue : : ResolvedType : : Integer ;
}
static bool is_dimension ( CalculatedStyleValue : : ResolvedType type )
{
return type ! = CalculatedStyleValue : : ResolvedType : : Number
& & type ! = CalculatedStyleValue : : ResolvedType : : Integer
& & type ! = CalculatedStyleValue : : ResolvedType : : Percentage ;
}
2023-05-27 23:50:33 +02:00
static double resolve_value_radians ( CalculatedStyleValue : : CalculationResult : : Value value )
{
return value . visit (
[ ] ( Number const & number ) { return number . value ( ) ; } ,
[ ] ( Angle const & angle ) { return angle . to_radians ( ) ; } ,
[ ] ( auto const & ) { VERIFY_NOT_REACHED ( ) ; return 0.0 ; } ) ;
2023-07-07 22:48:11 -04:00
}
2023-05-27 23:50:33 +02:00
2023-06-02 12:39:39 +02:00
static double resolve_value ( CalculatedStyleValue : : CalculationResult : : Value value , Optional < Length : : ResolutionContext const & > context )
2023-05-26 11:21:49 +02:00
{
return value . visit (
[ ] ( Number const & number ) { return number . value ( ) ; } ,
[ ] ( Angle const & angle ) { return angle . to_degrees ( ) ; } ,
2023-09-28 15:18:14 +01:00
[ ] ( Flex const & flex ) { return flex . to_fr ( ) ; } ,
2023-05-26 11:21:49 +02:00
[ ] ( Frequency const & frequency ) { return frequency . to_hertz ( ) ; } ,
2023-06-12 21:37:35 +03:00
[ & context ] ( Length const & length ) { return length . to_px ( * context ) . to_double ( ) ; } ,
2023-05-26 11:21:49 +02:00
[ ] ( Percentage const & percentage ) { return percentage . value ( ) ; } ,
2023-12-30 17:05:23 +00:00
[ ] ( Resolution const & resolution ) { return resolution . to_dots_per_pixel ( ) ; } ,
2023-05-26 11:21:49 +02:00
[ ] ( Time const & time ) { return time . to_seconds ( ) ; } ) ;
2023-07-07 22:48:11 -04:00
}
2023-05-26 11:21:49 +02:00
2023-07-05 19:58:13 +01:00
static Optional < CSSNumericType > add_the_types ( Vector < NonnullOwnPtr < CalculationNode > > const & nodes , PropertyID property_id )
{
Optional < CSSNumericType > left_type ;
for ( auto const & value : nodes ) {
auto right_type = value - > determine_type ( property_id ) ;
if ( ! right_type . has_value ( ) )
return { } ;
if ( left_type . has_value ( ) ) {
left_type = left_type - > added_to ( right_type . value ( ) ) ;
} else {
left_type = right_type ;
}
if ( ! left_type . has_value ( ) )
return { } ;
}
return left_type ;
}
2023-05-27 22:56:41 +02:00
static CalculatedStyleValue : : CalculationResult to_resolved_type ( CalculatedStyleValue : : ResolvedType type , double value )
{
switch ( type ) {
case CalculatedStyleValue : : ResolvedType : : Integer :
return { Number ( Number : : Type : : Integer , value ) } ;
case CalculatedStyleValue : : ResolvedType : : Number :
return { Number ( Number : : Type : : Number , value ) } ;
case CalculatedStyleValue : : ResolvedType : : Angle :
return { Angle : : make_degrees ( value ) } ;
2023-09-28 15:18:14 +01:00
case CalculatedStyleValue : : ResolvedType : : Flex :
return { Flex : : make_fr ( value ) } ;
2023-05-27 22:56:41 +02:00
case CalculatedStyleValue : : ResolvedType : : Frequency :
return { Frequency : : make_hertz ( value ) } ;
case CalculatedStyleValue : : ResolvedType : : Length :
2023-08-26 15:57:31 +01:00
return { Length : : make_px ( CSSPixels : : nearest_value_for ( value ) ) } ;
2023-05-27 22:56:41 +02:00
case CalculatedStyleValue : : ResolvedType : : Percentage :
return { Percentage ( value ) } ;
2023-12-30 17:05:23 +00:00
case CalculatedStyleValue : : ResolvedType : : Resolution :
return { Resolution : : make_dots_per_pixel ( value ) } ;
2023-05-27 22:56:41 +02:00
case CalculatedStyleValue : : ResolvedType : : Time :
return { Time : : make_seconds ( value ) } ;
}
VERIFY_NOT_REACHED ( ) ;
2023-07-07 22:48:11 -04:00
}
2023-05-27 22:56:41 +02:00
2023-07-08 16:55:06 +01:00
Optional < CalculationNode : : ConstantType > CalculationNode : : constant_type_from_string ( StringView string )
{
if ( string . equals_ignoring_ascii_case ( " e " sv ) )
return CalculationNode : : ConstantType : : E ;
if ( string . equals_ignoring_ascii_case ( " pi " sv ) )
return CalculationNode : : ConstantType : : Pi ;
if ( string . equals_ignoring_ascii_case ( " infinity " sv ) )
return CalculationNode : : ConstantType : : Infinity ;
if ( string . equals_ignoring_ascii_case ( " -infinity " sv ) )
return CalculationNode : : ConstantType : : MinusInfinity ;
if ( string . equals_ignoring_ascii_case ( " NaN " sv ) )
return CalculationNode : : ConstantType : : NaN ;
return { } ;
}
2023-04-11 15:48:06 +01:00
CalculationNode : : CalculationNode ( Type type )
: m_type ( type )
{
}
CalculationNode : : ~ CalculationNode ( ) = default ;
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < NumericCalculationNode > NumericCalculationNode : : create ( NumericValue value )
2023-04-11 15:48:06 +01:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) NumericCalculationNode ( move ( value ) ) ) ;
2023-04-11 15:48:06 +01:00
}
NumericCalculationNode : : NumericCalculationNode ( NumericValue value )
: CalculationNode ( Type : : Numeric )
, m_value ( move ( value ) )
{
}
NumericCalculationNode : : ~ NumericCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String NumericCalculationNode : : to_string ( ) const
2023-04-11 15:48:06 +01:00
{
return m_value . visit ( [ ] ( auto & value ) { return value . to_string ( ) ; } ) ;
}
Optional < CalculatedStyleValue : : ResolvedType > NumericCalculationNode : : resolved_type ( ) const
{
return m_value . visit (
[ ] ( Number const & ) { return CalculatedStyleValue : : ResolvedType : : Number ; } ,
[ ] ( Angle const & ) { return CalculatedStyleValue : : ResolvedType : : Angle ; } ,
2023-09-28 15:18:14 +01:00
[ ] ( Flex const & ) { return CalculatedStyleValue : : ResolvedType : : Flex ; } ,
2023-04-11 15:48:06 +01:00
[ ] ( Frequency const & ) { return CalculatedStyleValue : : ResolvedType : : Frequency ; } ,
[ ] ( Length const & ) { return CalculatedStyleValue : : ResolvedType : : Length ; } ,
[ ] ( Percentage const & ) { return CalculatedStyleValue : : ResolvedType : : Percentage ; } ,
2023-12-30 17:05:23 +00:00
[ ] ( Resolution const & ) { return CalculatedStyleValue : : ResolvedType : : Resolution ; } ,
2023-04-11 15:48:06 +01:00
[ ] ( Time const & ) { return CalculatedStyleValue : : ResolvedType : : Time ; } ) ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > NumericCalculationNode : : determine_type ( PropertyID property_id ) const
{
// Anything else is a terminal value, whose type is determined based on its CSS type:
return m_value . visit (
[ ] ( Number const & ) {
// -> <number>
// -> <integer>
// the type is «[ ]» (empty map)
return CSSNumericType { } ;
} ,
[ ] ( Length const & ) {
// -> <length>
// the type is «[ "length" → 1 ]»
return CSSNumericType { CSSNumericType : : BaseType : : Length , 1 } ;
} ,
[ ] ( Angle const & ) {
// -> <angle>
// the type is «[ "angle" → 1 ]»
return CSSNumericType { CSSNumericType : : BaseType : : Angle , 1 } ;
} ,
[ ] ( Time const & ) {
// -> <time>
// the type is «[ "time" → 1 ]»
return CSSNumericType { CSSNumericType : : BaseType : : Time , 1 } ;
} ,
[ ] ( Frequency const & ) {
// -> <frequency>
// the type is «[ "frequency" → 1 ]»
return CSSNumericType { CSSNumericType : : BaseType : : Frequency , 1 } ;
} ,
2023-12-30 17:05:23 +00:00
[ ] ( Resolution const & ) {
// -> <resolution>
// the type is «[ "resolution" → 1 ]»
return CSSNumericType { CSSNumericType : : BaseType : : Resolution , 1 } ;
} ,
2023-09-28 15:18:14 +01:00
[ ] ( Flex const & ) {
// -> <flex>
// the type is «[ "flex" → 1 ]»
return CSSNumericType { CSSNumericType : : BaseType : : Flex , 1 } ;
} ,
2023-07-05 19:58:13 +01:00
// NOTE: <calc-constant> is a separate node type. (FIXME: Should it be?)
[ property_id ] ( Percentage const & ) {
// -> <percentage>
// If, in the context in which the math function containing this calculation is placed,
// <percentage>s are resolved relative to another type of value (such as in width,
// where <percentage> is resolved against a <length>), and that other type is not <number>,
// the type is determined as the other type.
auto percentage_resolved_type = property_resolves_percentages_relative_to ( property_id ) ;
if ( percentage_resolved_type . has_value ( ) & & percentage_resolved_type ! = ValueType : : Number & & percentage_resolved_type ! = ValueType : : Percentage ) {
auto base_type = CSSNumericType : : base_type_from_value_type ( * percentage_resolved_type ) ;
VERIFY ( base_type . has_value ( ) ) ;
return CSSNumericType { base_type . value ( ) , 1 } ;
}
// Otherwise, the type is «[ "percent" → 1 ]».
return CSSNumericType { CSSNumericType : : BaseType : : Percent , 1 } ;
} ) ;
// In all cases, the associated percent hint is null.
}
2023-04-11 15:48:06 +01:00
bool NumericCalculationNode : : contains_percentage ( ) const
{
return m_value . has < Percentage > ( ) ;
}
2024-01-08 15:11:55 +01:00
CalculatedStyleValue : : CalculationResult NumericCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
if ( m_value . has < Percentage > ( ) ) {
2024-01-11 06:49:07 +01:00
// NOTE: Depending on whether percentage_basis is set, the caller of resolve() is expecting a raw percentage or
// resolved length.
2024-01-08 15:11:55 +01:00
return percentage_basis . visit (
[ & ] ( Empty const & ) - > CalculatedStyleValue : : CalculationResult {
2024-01-11 06:49:07 +01:00
return m_value ;
2024-01-08 15:11:55 +01:00
} ,
[ & ] ( auto const & value ) {
return CalculatedStyleValue : : CalculationResult ( value . percentage_of ( m_value . get < Percentage > ( ) ) ) ;
} ) ;
}
2023-04-11 15:48:06 +01:00
return m_value ;
}
2023-08-22 14:13:22 +01:00
void NumericCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-04-11 15:48:06 +01:00
{
2023-08-22 14:13:22 +01:00
builder . appendff ( " {: >{}}NUMERIC({}) \n " , " " , indent , m_value . visit ( [ ] ( auto & it ) { return it . to_string ( ) ; } ) ) ;
2023-04-11 15:48:06 +01:00
}
2024-01-09 12:41:43 +01:00
bool NumericCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_value = = static_cast < NumericCalculationNode const & > ( other ) . m_value ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < SumCalculationNode > SumCalculationNode : : create ( Vector < NonnullOwnPtr < CalculationNode > > values )
2023-04-11 15:48:06 +01:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) SumCalculationNode ( move ( values ) ) ) ;
2023-04-11 15:48:06 +01:00
}
SumCalculationNode : : SumCalculationNode ( Vector < NonnullOwnPtr < CalculationNode > > values )
: CalculationNode ( Type : : Sum )
, m_values ( move ( values ) )
{
VERIFY ( ! m_values . is_empty ( ) ) ;
}
SumCalculationNode : : ~ SumCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String SumCalculationNode : : to_string ( ) const
2023-04-11 15:48:06 +01:00
{
bool first = true ;
StringBuilder builder ;
for ( auto & value : m_values ) {
if ( ! first )
2023-08-22 14:08:15 +01:00
builder . append ( " + " sv ) ;
builder . append ( value - > to_string ( ) ) ;
2023-04-11 15:48:06 +01:00
first = false ;
}
2023-08-22 14:08:15 +01:00
return MUST ( builder . to_string ( ) ) ;
2023-04-11 15:48:06 +01:00
}
Optional < CalculatedStyleValue : : ResolvedType > SumCalculationNode : : resolved_type ( ) const
{
// FIXME: Implement https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
// For now, this is just ad-hoc, based on the old implementation.
Optional < CalculatedStyleValue : : ResolvedType > type ;
for ( auto const & value : m_values ) {
auto maybe_value_type = value - > resolved_type ( ) ;
if ( ! maybe_value_type . has_value ( ) )
return { } ;
auto value_type = maybe_value_type . value ( ) ;
if ( ! type . has_value ( ) ) {
type = value_type ;
continue ;
}
// At + or -, check that both sides have the same type, or that one side is a <number> and the other is an <integer>.
// If both sides are the same type, resolve to that type.
if ( value_type = = type )
continue ;
// If one side is a <number> and the other is an <integer>, resolve to <number>.
if ( is_number ( * type ) & & is_number ( value_type ) ) {
type = CalculatedStyleValue : : ResolvedType : : Number ;
continue ;
}
// FIXME: calc() handles <percentage> by allowing them to pretend to be whatever <dimension> type is allowed at this location.
// Since we can't easily check what that type is, we just allow <percentage> to combine with any other <dimension> type.
if ( type = = CalculatedStyleValue : : ResolvedType : : Percentage & & is_dimension ( value_type ) ) {
type = value_type ;
continue ;
}
if ( is_dimension ( * type ) & & value_type = = CalculatedStyleValue : : ResolvedType : : Percentage )
continue ;
return { } ;
}
return type ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > SumCalculationNode : : determine_type ( PropertyID property_id ) const
{
// At a + or - sub-expression, attempt to add the types of the left and right arguments.
// If this returns failure, the entire calculation’ s type is failure.
// Otherwise, the sub-expression’ s type is the returned type.
return add_the_types ( m_values , property_id ) ;
}
2023-04-11 15:48:06 +01:00
bool SumCalculationNode : : contains_percentage ( ) const
{
for ( auto const & value : m_values ) {
if ( value - > contains_percentage ( ) )
return true ;
}
return false ;
}
2023-06-02 12:39:39 +02:00
CalculatedStyleValue : : CalculationResult SumCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
2023-04-11 15:48:06 +01:00
{
Optional < CalculatedStyleValue : : CalculationResult > total ;
for ( auto & additional_product : m_values ) {
2023-06-02 12:39:39 +02:00
auto additional_value = additional_product - > resolve ( context , percentage_basis ) ;
2023-04-11 15:48:06 +01:00
if ( ! total . has_value ( ) ) {
total = additional_value ;
continue ;
}
2023-06-02 12:39:39 +02:00
total - > add ( additional_value , context , percentage_basis ) ;
2023-04-11 15:48:06 +01:00
}
return total . value ( ) ;
}
2023-08-19 15:20:23 +01:00
void SumCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-04-11 15:48:06 +01:00
{
for ( auto & item : m_values ) {
2023-08-19 15:20:23 +01:00
item - > for_each_child_node ( callback ) ;
callback ( item ) ;
2023-04-11 15:48:06 +01:00
}
}
2023-08-22 14:13:22 +01:00
void SumCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-04-11 15:48:06 +01:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}SUM: \n " , " " , indent ) ;
2023-04-11 15:48:06 +01:00
for ( auto const & item : m_values )
2023-08-22 14:13:22 +01:00
item - > dump ( builder , indent + 2 ) ;
2023-04-11 15:48:06 +01:00
}
2024-01-09 12:41:43 +01:00
bool SumCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
for ( size_t i = 0 ; i < m_values . size ( ) ; + + i ) {
if ( ! m_values [ i ] - > equals ( * static_cast < SumCalculationNode const & > ( other ) . m_values [ i ] ) )
return false ;
}
return true ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < ProductCalculationNode > ProductCalculationNode : : create ( Vector < NonnullOwnPtr < CalculationNode > > values )
2023-04-11 15:48:06 +01:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) ProductCalculationNode ( move ( values ) ) ) ;
2023-04-11 15:48:06 +01:00
}
ProductCalculationNode : : ProductCalculationNode ( Vector < NonnullOwnPtr < CalculationNode > > values )
: CalculationNode ( Type : : Product )
, m_values ( move ( values ) )
{
VERIFY ( ! m_values . is_empty ( ) ) ;
}
ProductCalculationNode : : ~ ProductCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String ProductCalculationNode : : to_string ( ) const
2023-04-11 15:48:06 +01:00
{
bool first = true ;
StringBuilder builder ;
for ( auto & value : m_values ) {
if ( ! first )
2023-08-22 14:08:15 +01:00
builder . append ( " * " sv ) ;
builder . append ( value - > to_string ( ) ) ;
2023-04-11 15:48:06 +01:00
first = false ;
}
2023-08-22 14:08:15 +01:00
return MUST ( builder . to_string ( ) ) ;
2023-04-11 15:48:06 +01:00
}
Optional < CalculatedStyleValue : : ResolvedType > ProductCalculationNode : : resolved_type ( ) const
{
// FIXME: Implement https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
// For now, this is just ad-hoc, based on the old implementation.
Optional < CalculatedStyleValue : : ResolvedType > type ;
for ( auto const & value : m_values ) {
auto maybe_value_type = value - > resolved_type ( ) ;
if ( ! maybe_value_type . has_value ( ) )
return { } ;
auto value_type = maybe_value_type . value ( ) ;
if ( ! type . has_value ( ) ) {
type = value_type ;
continue ;
}
// At *, check that at least one side is <number>.
if ( ! ( is_number ( * type ) | | is_number ( value_type ) ) )
return { } ;
// If both sides are <integer>, resolve to <integer>.
if ( type = = CalculatedStyleValue : : ResolvedType : : Integer & & value_type = = CalculatedStyleValue : : ResolvedType : : Integer ) {
type = CalculatedStyleValue : : ResolvedType : : Integer ;
} else {
// Otherwise, resolve to the type of the other side.
if ( is_number ( * type ) )
type = value_type ;
}
}
return type ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > ProductCalculationNode : : determine_type ( PropertyID property_id ) const
{
// At a * sub-expression, multiply the types of the left and right arguments.
// The sub-expression’ s type is the returned result.
Optional < CSSNumericType > left_type ;
for ( auto const & value : m_values ) {
auto right_type = value - > determine_type ( property_id ) ;
if ( ! right_type . has_value ( ) )
return { } ;
if ( left_type . has_value ( ) ) {
left_type = left_type - > multiplied_by ( right_type . value ( ) ) ;
} else {
left_type = right_type ;
}
if ( ! left_type . has_value ( ) )
return { } ;
}
return left_type ;
}
2023-04-11 15:48:06 +01:00
bool ProductCalculationNode : : contains_percentage ( ) const
{
for ( auto const & value : m_values ) {
if ( value - > contains_percentage ( ) )
return true ;
}
return false ;
}
2023-06-02 12:39:39 +02:00
CalculatedStyleValue : : CalculationResult ProductCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
2023-04-11 15:48:06 +01:00
{
Optional < CalculatedStyleValue : : CalculationResult > total ;
for ( auto & additional_product : m_values ) {
2023-06-02 12:39:39 +02:00
auto additional_value = additional_product - > resolve ( context , percentage_basis ) ;
2023-04-11 15:48:06 +01:00
if ( ! total . has_value ( ) ) {
total = additional_value ;
continue ;
}
2023-06-02 12:39:39 +02:00
total - > multiply_by ( additional_value , context ) ;
2023-04-11 15:48:06 +01:00
}
return total . value ( ) ;
}
2023-08-19 15:20:23 +01:00
void ProductCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-04-11 15:48:06 +01:00
{
for ( auto & item : m_values ) {
2023-08-19 15:20:23 +01:00
item - > for_each_child_node ( callback ) ;
callback ( item ) ;
2023-04-11 15:48:06 +01:00
}
}
2023-08-22 14:13:22 +01:00
void ProductCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-04-11 15:48:06 +01:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}PRODUCT: \n " , " " , indent ) ;
2023-04-11 15:48:06 +01:00
for ( auto const & item : m_values )
2023-08-22 14:13:22 +01:00
item - > dump ( builder , indent + 2 ) ;
2023-04-11 15:48:06 +01:00
}
2024-01-09 12:41:43 +01:00
bool ProductCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
for ( size_t i = 0 ; i < m_values . size ( ) ; + + i ) {
if ( ! m_values [ i ] - > equals ( * static_cast < ProductCalculationNode const & > ( other ) . m_values [ i ] ) )
return false ;
}
return true ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < NegateCalculationNode > NegateCalculationNode : : create ( NonnullOwnPtr < Web : : CSS : : CalculationNode > value )
2023-04-11 15:48:06 +01:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) NegateCalculationNode ( move ( value ) ) ) ;
2023-04-11 15:48:06 +01:00
}
NegateCalculationNode : : NegateCalculationNode ( NonnullOwnPtr < CalculationNode > value )
: CalculationNode ( Type : : Negate )
, m_value ( move ( value ) )
{
}
NegateCalculationNode : : ~ NegateCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String NegateCalculationNode : : to_string ( ) const
2023-04-11 15:48:06 +01:00
{
2023-08-22 14:08:15 +01:00
return MUST ( String : : formatted ( " (0 - {}) " , m_value->to_string())) ;
2023-04-11 15:48:06 +01:00
}
Optional < CalculatedStyleValue : : ResolvedType > NegateCalculationNode : : resolved_type ( ) const
{
return m_value - > resolved_type ( ) ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > NegateCalculationNode : : determine_type ( PropertyID property_id ) const
{
// NOTE: `- foo` doesn't change the type
return m_value - > determine_type ( property_id ) ;
}
2023-04-11 15:48:06 +01:00
bool NegateCalculationNode : : contains_percentage ( ) const
{
return m_value - > contains_percentage ( ) ;
}
2023-06-02 12:39:39 +02:00
CalculatedStyleValue : : CalculationResult NegateCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
2023-04-11 15:48:06 +01:00
{
2023-06-02 12:39:39 +02:00
auto child_value = m_value - > resolve ( context , percentage_basis ) ;
2023-04-11 15:48:06 +01:00
child_value . negate ( ) ;
return child_value ;
}
2023-08-19 15:20:23 +01:00
void NegateCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-04-11 15:48:06 +01:00
{
2023-08-19 15:20:23 +01:00
m_value - > for_each_child_node ( callback ) ;
callback ( m_value ) ;
2023-04-11 15:48:06 +01:00
}
2023-08-22 14:13:22 +01:00
void NegateCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-04-11 15:48:06 +01:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}NEGATE: \n " , " " , indent ) ;
2023-08-22 14:13:22 +01:00
m_value - > dump ( builder , indent + 2 ) ;
2023-04-11 15:48:06 +01:00
}
2024-01-09 12:41:43 +01:00
bool NegateCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_value - > equals ( * static_cast < NegateCalculationNode const & > ( other ) . m_value ) ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < InvertCalculationNode > InvertCalculationNode : : create ( NonnullOwnPtr < Web : : CSS : : CalculationNode > value )
2023-04-11 15:48:06 +01:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) InvertCalculationNode ( move ( value ) ) ) ;
2023-04-11 15:48:06 +01:00
}
InvertCalculationNode : : InvertCalculationNode ( NonnullOwnPtr < CalculationNode > value )
: CalculationNode ( Type : : Invert )
, m_value ( move ( value ) )
{
}
InvertCalculationNode : : ~ InvertCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String InvertCalculationNode : : to_string ( ) const
2023-04-11 15:48:06 +01:00
{
2023-08-22 14:08:15 +01:00
return MUST ( String : : formatted ( " (1 / {}) " , m_value->to_string())) ;
2023-04-11 15:48:06 +01:00
}
Optional < CalculatedStyleValue : : ResolvedType > InvertCalculationNode : : resolved_type ( ) const
{
auto type = m_value - > resolved_type ( ) ;
if ( type = = CalculatedStyleValue : : ResolvedType : : Integer )
return CalculatedStyleValue : : ResolvedType : : Number ;
return type ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > InvertCalculationNode : : determine_type ( PropertyID property_id ) const
{
// At a / sub-expression, let left type be the result of finding the types of its left argument,
// and right type be the result of finding the types of its right argument and then inverting it.
// The sub-expression’ s type is the result of multiplying the left type and right type.
// NOTE: An InvertCalculationNode only represents the right argument here, and the multiplication
// is handled in the parent ProductCalculationNode.
return m_value - > determine_type ( property_id ) . map ( [ ] ( auto & it ) { return it . inverted ( ) ; } ) ;
}
2023-04-11 15:48:06 +01:00
bool InvertCalculationNode : : contains_percentage ( ) const
{
return m_value - > contains_percentage ( ) ;
}
2023-06-02 12:39:39 +02:00
CalculatedStyleValue : : CalculationResult InvertCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
2023-04-11 15:48:06 +01:00
{
2023-06-02 12:39:39 +02:00
auto child_value = m_value - > resolve ( context , percentage_basis ) ;
2023-04-11 15:48:06 +01:00
child_value . invert ( ) ;
return child_value ;
}
2023-08-19 15:20:23 +01:00
void InvertCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-04-11 15:48:06 +01:00
{
2023-08-19 15:20:23 +01:00
m_value - > for_each_child_node ( callback ) ;
callback ( m_value ) ;
2023-04-11 15:48:06 +01:00
}
2023-08-22 14:13:22 +01:00
void InvertCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-04-11 15:48:06 +01:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}INVERT: \n " , " " , indent ) ;
2023-08-22 14:13:22 +01:00
m_value - > dump ( builder , indent + 2 ) ;
2023-04-11 15:48:06 +01:00
}
2024-01-09 12:41:43 +01:00
bool InvertCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_value - > equals ( * static_cast < InvertCalculationNode const & > ( other ) . m_value ) ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < MinCalculationNode > MinCalculationNode : : create ( Vector < NonnullOwnPtr < Web : : CSS : : CalculationNode > > values )
2023-05-26 11:21:49 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) MinCalculationNode ( move ( values ) ) ) ;
2023-05-26 11:21:49 +02:00
}
MinCalculationNode : : MinCalculationNode ( Vector < NonnullOwnPtr < CalculationNode > > values )
: CalculationNode ( Type : : Min )
, m_values ( move ( values ) )
{
}
MinCalculationNode : : ~ MinCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String MinCalculationNode : : to_string ( ) const
2023-05-26 11:21:49 +02:00
{
StringBuilder builder ;
2023-08-22 14:08:15 +01:00
builder . append ( " min( " sv ) ;
2023-05-26 11:21:49 +02:00
for ( size_t i = 0 ; i < m_values . size ( ) ; + + i ) {
if ( i ! = 0 )
2023-08-22 14:08:15 +01:00
builder . append ( " , " sv ) ;
builder . append ( m_values [ i ] - > to_string ( ) ) ;
2023-05-26 11:21:49 +02:00
}
2023-08-22 14:08:15 +01:00
builder . append ( " ) " sv ) ;
return MUST ( builder . to_string ( ) ) ;
2023-05-26 11:21:49 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > MinCalculationNode : : resolved_type ( ) const
{
// NOTE: We check during parsing that all values have the same type.
return m_values [ 0 ] - > resolved_type ( ) ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > MinCalculationNode : : determine_type ( PropertyID property_id ) const
{
// The result of adding the types of its comma-separated calculations.
return add_the_types ( m_values , property_id ) ;
}
2023-05-26 11:21:49 +02:00
bool MinCalculationNode : : contains_percentage ( ) const
{
for ( auto const & value : m_values ) {
if ( value - > contains_percentage ( ) )
return true ;
}
return false ;
}
2023-06-02 12:39:39 +02:00
CalculatedStyleValue : : CalculationResult MinCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
2023-05-26 11:21:49 +02:00
{
2023-06-02 12:39:39 +02:00
CalculatedStyleValue : : CalculationResult smallest_node = m_values . first ( ) - > resolve ( context , percentage_basis ) ;
auto smallest_value = resolve_value ( smallest_node . value ( ) , context ) ;
2023-05-26 11:21:49 +02:00
for ( size_t i = 1 ; i < m_values . size ( ) ; i + + ) {
2023-06-02 12:39:39 +02:00
auto child_resolved = m_values [ i ] - > resolve ( context , percentage_basis ) ;
auto child_value = resolve_value ( child_resolved . value ( ) , context ) ;
2023-05-26 11:21:49 +02:00
if ( child_value < smallest_value ) {
smallest_value = child_value ;
smallest_node = child_resolved ;
}
}
return smallest_node ;
}
2023-08-19 15:20:23 +01:00
void MinCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-26 11:21:49 +02:00
{
for ( auto & value : m_values ) {
2023-08-19 15:20:23 +01:00
value - > for_each_child_node ( callback ) ;
callback ( value ) ;
2023-05-26 11:21:49 +02:00
}
}
2023-08-22 14:13:22 +01:00
void MinCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-26 11:21:49 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}MIN: \n " , " " , indent ) ;
2023-05-26 11:21:49 +02:00
for ( auto const & value : m_values )
2023-08-22 14:13:22 +01:00
value - > dump ( builder , indent + 2 ) ;
2023-05-26 11:21:49 +02:00
}
2024-01-09 12:41:43 +01:00
bool MinCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
for ( size_t i = 0 ; i < m_values . size ( ) ; + + i ) {
if ( ! m_values [ i ] - > equals ( * static_cast < MinCalculationNode const & > ( other ) . m_values [ i ] ) )
return false ;
}
return true ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < MaxCalculationNode > MaxCalculationNode : : create ( Vector < NonnullOwnPtr < Web : : CSS : : CalculationNode > > values )
2023-05-26 15:00:22 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) MaxCalculationNode ( move ( values ) ) ) ;
2023-05-26 15:00:22 +02:00
}
MaxCalculationNode : : MaxCalculationNode ( Vector < NonnullOwnPtr < CalculationNode > > values )
: CalculationNode ( Type : : Max )
, m_values ( move ( values ) )
{
}
MaxCalculationNode : : ~ MaxCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String MaxCalculationNode : : to_string ( ) const
2023-05-26 15:00:22 +02:00
{
StringBuilder builder ;
2023-08-22 14:08:15 +01:00
builder . append ( " max( " sv ) ;
2023-05-26 15:00:22 +02:00
for ( size_t i = 0 ; i < m_values . size ( ) ; + + i ) {
if ( i ! = 0 )
2023-08-22 14:08:15 +01:00
builder . append ( " , " sv ) ;
builder . append ( m_values [ i ] - > to_string ( ) ) ;
2023-05-26 15:00:22 +02:00
}
2023-08-22 14:08:15 +01:00
builder . append ( " ) " sv ) ;
return MUST ( builder . to_string ( ) ) ;
2023-05-26 15:00:22 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > MaxCalculationNode : : resolved_type ( ) const
{
// NOTE: We check during parsing that all values have the same type.
return m_values [ 0 ] - > resolved_type ( ) ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > MaxCalculationNode : : determine_type ( PropertyID property_id ) const
{
// The result of adding the types of its comma-separated calculations.
return add_the_types ( m_values , property_id ) ;
}
2023-05-26 15:00:22 +02:00
bool MaxCalculationNode : : contains_percentage ( ) const
{
for ( auto const & value : m_values ) {
if ( value - > contains_percentage ( ) )
return true ;
}
return false ;
}
2023-06-02 12:39:39 +02:00
CalculatedStyleValue : : CalculationResult MaxCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
2023-05-26 15:00:22 +02:00
{
2023-06-02 12:39:39 +02:00
CalculatedStyleValue : : CalculationResult largest_node = m_values . first ( ) - > resolve ( context , percentage_basis ) ;
auto largest_value = resolve_value ( largest_node . value ( ) , context ) ;
2023-05-26 15:00:22 +02:00
for ( size_t i = 1 ; i < m_values . size ( ) ; i + + ) {
2023-06-02 12:39:39 +02:00
auto child_resolved = m_values [ i ] - > resolve ( context , percentage_basis ) ;
auto child_value = resolve_value ( child_resolved . value ( ) , context ) ;
2023-05-26 15:00:22 +02:00
if ( child_value > largest_value ) {
largest_value = child_value ;
largest_node = child_resolved ;
}
}
return largest_node ;
}
2023-08-19 15:20:23 +01:00
void MaxCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-26 15:00:22 +02:00
{
for ( auto & value : m_values ) {
2023-08-19 15:20:23 +01:00
value - > for_each_child_node ( callback ) ;
callback ( value ) ;
2023-05-26 15:00:22 +02:00
}
}
2023-08-22 14:13:22 +01:00
void MaxCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-26 15:00:22 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}MAX: \n " , " " , indent ) ;
2023-05-26 15:00:22 +02:00
for ( auto const & value : m_values )
2023-08-22 14:13:22 +01:00
value - > dump ( builder , indent + 2 ) ;
2023-05-26 15:00:22 +02:00
}
2024-01-09 12:41:43 +01:00
bool MaxCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
for ( size_t i = 0 ; i < m_values . size ( ) ; + + i ) {
if ( ! m_values [ i ] - > equals ( * static_cast < MaxCalculationNode const & > ( other ) . m_values [ i ] ) )
return false ;
}
return true ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < ClampCalculationNode > ClampCalculationNode : : create ( NonnullOwnPtr < CalculationNode > min , NonnullOwnPtr < CalculationNode > center , NonnullOwnPtr < CalculationNode > max )
2023-05-26 15:40:39 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) ClampCalculationNode ( move ( min ) , move ( center ) , move ( max ) ) ) ;
2023-05-26 15:40:39 +02:00
}
ClampCalculationNode : : ClampCalculationNode ( NonnullOwnPtr < CalculationNode > min , NonnullOwnPtr < CalculationNode > center , NonnullOwnPtr < CalculationNode > max )
: CalculationNode ( Type : : Clamp )
, m_min_value ( move ( min ) )
, m_center_value ( move ( center ) )
, m_max_value ( move ( max ) )
{
}
ClampCalculationNode : : ~ ClampCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String ClampCalculationNode : : to_string ( ) const
2023-05-26 15:40:39 +02:00
{
StringBuilder builder ;
2023-08-22 14:08:15 +01:00
builder . append ( " clamp( " sv ) ;
builder . append ( m_min_value - > to_string ( ) ) ;
builder . append ( " , " sv ) ;
builder . append ( m_center_value - > to_string ( ) ) ;
builder . append ( " , " sv ) ;
builder . append ( m_max_value - > to_string ( ) ) ;
builder . append ( " ) " sv ) ;
return MUST ( builder . to_string ( ) ) ;
2023-05-26 15:40:39 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > ClampCalculationNode : : resolved_type ( ) const
{
// NOTE: We check during parsing that all values have the same type.
return m_min_value - > resolved_type ( ) ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > ClampCalculationNode : : determine_type ( PropertyID property_id ) const
{
// The result of adding the types of its comma-separated calculations.
auto min_type = m_min_value - > determine_type ( property_id ) ;
auto center_type = m_center_value - > determine_type ( property_id ) ;
auto max_type = m_max_value - > determine_type ( property_id ) ;
if ( ! min_type . has_value ( ) | | ! center_type . has_value ( ) | | ! max_type . has_value ( ) )
return { } ;
auto result = min_type - > added_to ( * center_type ) ;
if ( ! result . has_value ( ) )
return { } ;
return result - > added_to ( * max_type ) ;
}
2023-05-26 15:40:39 +02:00
bool ClampCalculationNode : : contains_percentage ( ) const
{
return m_min_value - > contains_percentage ( ) | | m_center_value - > contains_percentage ( ) | | m_max_value - > contains_percentage ( ) ;
}
2023-06-02 12:39:39 +02:00
CalculatedStyleValue : : CalculationResult ClampCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
2023-05-26 15:40:39 +02:00
{
2023-06-02 12:39:39 +02:00
auto min_node = m_min_value - > resolve ( context , percentage_basis ) ;
auto center_node = m_center_value - > resolve ( context , percentage_basis ) ;
auto max_node = m_max_value - > resolve ( context , percentage_basis ) ;
2023-05-26 15:40:39 +02:00
2023-06-02 12:39:39 +02:00
auto min_value = resolve_value ( min_node . value ( ) , context ) ;
auto center_value = resolve_value ( center_node . value ( ) , context ) ;
auto max_value = resolve_value ( max_node . value ( ) , context ) ;
2023-05-26 15:40:39 +02:00
// NOTE: The value should be returned as "max(MIN, min(VAL, MAX))"
auto chosen_value = max ( min_value , min ( center_value , max_value ) ) ;
if ( chosen_value = = min_value )
return min_node ;
if ( chosen_value = = center_value )
return center_node ;
if ( chosen_value = = max_value )
return max_node ;
VERIFY_NOT_REACHED ( ) ;
}
2023-08-19 15:20:23 +01:00
void ClampCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-26 15:40:39 +02:00
{
2023-08-19 15:20:23 +01:00
m_min_value - > for_each_child_node ( callback ) ;
m_center_value - > for_each_child_node ( callback ) ;
m_max_value - > for_each_child_node ( callback ) ;
callback ( m_min_value ) ;
callback ( m_center_value ) ;
callback ( m_max_value ) ;
2023-05-26 15:40:39 +02:00
}
2023-08-22 14:13:22 +01:00
void ClampCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-26 15:40:39 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}CLAMP: \n " , " " , indent ) ;
2023-08-22 14:13:22 +01:00
m_min_value - > dump ( builder , indent + 2 ) ;
m_center_value - > dump ( builder , indent + 2 ) ;
m_max_value - > dump ( builder , indent + 2 ) ;
2023-05-26 15:40:39 +02:00
}
2024-01-09 12:41:43 +01:00
bool ClampCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_min_value - > equals ( * static_cast < ClampCalculationNode const & > ( other ) . m_min_value )
& & m_center_value - > equals ( * static_cast < ClampCalculationNode const & > ( other ) . m_center_value )
& & m_max_value - > equals ( * static_cast < ClampCalculationNode const & > ( other ) . m_max_value ) ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < AbsCalculationNode > AbsCalculationNode : : create ( NonnullOwnPtr < CalculationNode > value )
2023-05-27 22:56:41 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) AbsCalculationNode ( move ( value ) ) ) ;
2023-05-27 22:56:41 +02:00
}
AbsCalculationNode : : AbsCalculationNode ( NonnullOwnPtr < CalculationNode > value )
: CalculationNode ( Type : : Abs )
, m_value ( move ( value ) )
{
}
AbsCalculationNode : : ~ AbsCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String AbsCalculationNode : : to_string ( ) const
2023-05-27 22:56:41 +02:00
{
StringBuilder builder ;
builder . append ( " abs( " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_value - > to_string ( ) ) ;
2023-05-27 22:56:41 +02:00
builder . append ( " ) " sv ) ;
2023-08-22 14:08:15 +01:00
return MUST ( builder . to_string ( ) ) ;
2023-05-27 22:56:41 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > AbsCalculationNode : : resolved_type ( ) const
{
return m_value - > resolved_type ( ) ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > AbsCalculationNode : : determine_type ( PropertyID property_id ) const
{
// The type of its contained calculation.
return m_value - > determine_type ( property_id ) ;
}
2023-05-27 22:56:41 +02:00
bool AbsCalculationNode : : contains_percentage ( ) const
{
return m_value - > contains_percentage ( ) ;
}
CalculatedStyleValue : : CalculationResult AbsCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
auto resolved_type = m_value - > resolved_type ( ) . value ( ) ;
auto node_a = m_value - > resolve ( context , percentage_basis ) ;
auto node_a_value = resolve_value ( node_a . value ( ) , context ) ;
if ( node_a_value < 0 )
return to_resolved_type ( resolved_type , - node_a_value ) ;
return node_a ;
}
2023-08-19 15:20:23 +01:00
void AbsCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-27 22:56:41 +02:00
{
2023-08-19 15:20:23 +01:00
m_value - > for_each_child_node ( callback ) ;
callback ( m_value ) ;
2023-05-27 22:56:41 +02:00
}
2023-08-22 14:13:22 +01:00
void AbsCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-27 22:56:41 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}ABS: {} \n " , " " , indent , to_string ( ) ) ;
2023-05-27 22:56:41 +02:00
}
2024-01-09 12:41:43 +01:00
bool AbsCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_value - > equals ( * static_cast < AbsCalculationNode const & > ( other ) . m_value ) ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < SignCalculationNode > SignCalculationNode : : create ( NonnullOwnPtr < CalculationNode > value )
2023-05-27 23:02:39 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) SignCalculationNode ( move ( value ) ) ) ;
2023-05-27 23:02:39 +02:00
}
SignCalculationNode : : SignCalculationNode ( NonnullOwnPtr < CalculationNode > value )
: CalculationNode ( Type : : Sign )
, m_value ( move ( value ) )
{
}
SignCalculationNode : : ~ SignCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String SignCalculationNode : : to_string ( ) const
2023-05-27 23:02:39 +02:00
{
StringBuilder builder ;
builder . append ( " sign( " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_value - > to_string ( ) ) ;
2023-05-27 23:02:39 +02:00
builder . append ( " ) " sv ) ;
2023-08-22 14:08:15 +01:00
return MUST ( builder . to_string ( ) ) ;
2023-05-27 23:02:39 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > SignCalculationNode : : resolved_type ( ) const
{
return CalculatedStyleValue : : ResolvedType : : Integer ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > SignCalculationNode : : determine_type ( PropertyID ) const
{
// «[ ]» (empty map).
return CSSNumericType { } ;
}
2023-05-27 23:02:39 +02:00
bool SignCalculationNode : : contains_percentage ( ) const
{
return m_value - > contains_percentage ( ) ;
}
CalculatedStyleValue : : CalculationResult SignCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
auto node_a = m_value - > resolve ( context , percentage_basis ) ;
auto node_a_value = resolve_value ( node_a . value ( ) , context ) ;
if ( node_a_value < 0 )
return { Number ( Number : : Type : : Integer , - 1 ) } ;
if ( node_a_value > 0 )
return { Number ( Number : : Type : : Integer , 1 ) } ;
return { Number ( Number : : Type : : Integer , 0 ) } ;
}
2023-08-19 15:20:23 +01:00
void SignCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-27 23:02:39 +02:00
{
2023-08-19 15:20:23 +01:00
m_value - > for_each_child_node ( callback ) ;
callback ( m_value ) ;
2023-05-27 23:02:39 +02:00
}
2023-08-22 14:13:22 +01:00
void SignCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-27 23:02:39 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}SIGN: {} \n " , " " , indent , to_string ( ) ) ;
2023-05-27 23:02:39 +02:00
}
2024-01-09 12:41:43 +01:00
bool SignCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_value - > equals ( * static_cast < SignCalculationNode const & > ( other ) . m_value ) ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < ConstantCalculationNode > ConstantCalculationNode : : create ( ConstantType constant )
2023-05-26 21:24:31 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) ConstantCalculationNode ( constant ) ) ;
2023-05-26 21:24:31 +02:00
}
ConstantCalculationNode : : ConstantCalculationNode ( ConstantType constant )
: CalculationNode ( Type : : Constant )
, m_constant ( constant )
{
}
ConstantCalculationNode : : ~ ConstantCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String ConstantCalculationNode : : to_string ( ) const
2023-05-26 21:24:31 +02:00
{
switch ( m_constant ) {
case CalculationNode : : ConstantType : : E :
2023-08-07 22:26:17 -04:00
return " e " _string ;
2023-07-08 16:55:06 +01:00
case CalculationNode : : ConstantType : : Pi :
2023-08-07 22:26:17 -04:00
return " pi " _string ;
2023-05-26 21:24:31 +02:00
case CalculationNode : : ConstantType : : Infinity :
return " infinity " _string ;
case CalculationNode : : ConstantType : : MinusInfinity :
return " -infinity " _string ;
case CalculationNode : : ConstantType : : NaN :
return " NaN " _string ;
}
VERIFY_NOT_REACHED ( ) ;
}
Optional < CalculatedStyleValue : : ResolvedType > ConstantCalculationNode : : resolved_type ( ) const
{
return CalculatedStyleValue : : ResolvedType : : Number ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > ConstantCalculationNode : : determine_type ( PropertyID ) const
{
// Anything else is a terminal value, whose type is determined based on its CSS type:
// -> <calc-constant>
// the type is «[ ]» (empty map)
return CSSNumericType { } ;
}
2023-05-26 21:24:31 +02:00
CalculatedStyleValue : : CalculationResult ConstantCalculationNode : : resolve ( [[maybe_unused]] Optional<Length::ResolutionContext const&> context, [[maybe_unused]] CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
switch ( m_constant ) {
case CalculationNode : : ConstantType : : E :
return { Number ( Number : : Type : : Number , M_E ) } ;
2023-07-08 16:55:06 +01:00
case CalculationNode : : ConstantType : : Pi :
2023-05-26 21:24:31 +02:00
return { Number ( Number : : Type : : Number , M_PI ) } ;
// FIXME: We need to keep track of Infinity and NaN across all nodes, since they require special handling.
case CalculationNode : : ConstantType : : Infinity :
2023-08-20 13:05:23 +01:00
return { Number ( Number : : Type : : Number , NumericLimits < double > : : max ( ) ) } ;
2023-05-26 21:24:31 +02:00
case CalculationNode : : ConstantType : : MinusInfinity :
2023-08-20 13:05:23 +01:00
return { Number ( Number : : Type : : Number , NumericLimits < double > : : lowest ( ) ) } ;
2023-05-26 21:24:31 +02:00
case CalculationNode : : ConstantType : : NaN :
return { Number ( Number : : Type : : Number , NAN ) } ;
}
VERIFY_NOT_REACHED ( ) ;
}
2023-08-22 14:13:22 +01:00
void ConstantCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-26 21:24:31 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}CONSTANT: {} \n " , " " , indent , to_string ( ) ) ;
2023-05-26 21:24:31 +02:00
}
2024-01-09 12:41:43 +01:00
bool ConstantCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_constant = = static_cast < ConstantCalculationNode const & > ( other ) . m_constant ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < SinCalculationNode > SinCalculationNode : : create ( NonnullOwnPtr < CalculationNode > value )
2023-05-27 23:50:33 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) SinCalculationNode ( move ( value ) ) ) ;
2023-05-27 23:50:33 +02:00
}
SinCalculationNode : : SinCalculationNode ( NonnullOwnPtr < CalculationNode > value )
: CalculationNode ( Type : : Sin )
, m_value ( move ( value ) )
{
}
SinCalculationNode : : ~ SinCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String SinCalculationNode : : to_string ( ) const
2023-05-27 23:50:33 +02:00
{
StringBuilder builder ;
builder . append ( " sin( " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_value - > to_string ( ) ) ;
2023-05-27 23:50:33 +02:00
builder . append ( " ) " sv ) ;
2023-08-22 14:08:15 +01:00
return MUST ( builder . to_string ( ) ) ;
2023-05-27 23:50:33 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > SinCalculationNode : : resolved_type ( ) const
{
return CalculatedStyleValue : : ResolvedType : : Number ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > SinCalculationNode : : determine_type ( PropertyID ) const
{
// «[ ]» (empty map).
return CSSNumericType { } ;
}
2023-05-27 23:50:33 +02:00
bool SinCalculationNode : : contains_percentage ( ) const
{
return m_value - > contains_percentage ( ) ;
}
CalculatedStyleValue : : CalculationResult SinCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
auto node_a = m_value - > resolve ( context , percentage_basis ) ;
auto node_a_value = resolve_value_radians ( node_a . value ( ) ) ;
auto result = sin ( node_a_value ) ;
return { Number ( Number : : Type : : Number , result ) } ;
}
2023-08-19 15:20:23 +01:00
void SinCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-27 23:50:33 +02:00
{
2023-08-19 15:20:23 +01:00
m_value - > for_each_child_node ( callback ) ;
callback ( m_value ) ;
2023-05-27 23:50:33 +02:00
}
2023-08-22 14:13:22 +01:00
void SinCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-27 23:50:33 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}SIN: {} \n " , " " , indent , to_string ( ) ) ;
2023-05-27 23:50:33 +02:00
}
2024-01-09 12:41:43 +01:00
bool SinCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_value - > equals ( * static_cast < SinCalculationNode const & > ( other ) . m_value ) ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < CosCalculationNode > CosCalculationNode : : create ( NonnullOwnPtr < CalculationNode > value )
2023-05-27 23:57:01 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) CosCalculationNode ( move ( value ) ) ) ;
2023-05-27 23:57:01 +02:00
}
CosCalculationNode : : CosCalculationNode ( NonnullOwnPtr < CalculationNode > value )
: CalculationNode ( Type : : Cos )
, m_value ( move ( value ) )
{
}
CosCalculationNode : : ~ CosCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String CosCalculationNode : : to_string ( ) const
2023-05-27 23:57:01 +02:00
{
StringBuilder builder ;
builder . append ( " cos( " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_value - > to_string ( ) ) ;
2023-05-27 23:57:01 +02:00
builder . append ( " ) " sv ) ;
2023-08-22 14:08:15 +01:00
return MUST ( builder . to_string ( ) ) ;
2023-05-27 23:57:01 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > CosCalculationNode : : resolved_type ( ) const
{
return CalculatedStyleValue : : ResolvedType : : Number ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > CosCalculationNode : : determine_type ( PropertyID ) const
{
// «[ ]» (empty map).
return CSSNumericType { } ;
}
2023-05-27 23:57:01 +02:00
bool CosCalculationNode : : contains_percentage ( ) const
{
return m_value - > contains_percentage ( ) ;
}
CalculatedStyleValue : : CalculationResult CosCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
auto node_a = m_value - > resolve ( context , percentage_basis ) ;
auto node_a_value = resolve_value_radians ( node_a . value ( ) ) ;
auto result = cos ( node_a_value ) ;
return { Number ( Number : : Type : : Number , result ) } ;
}
2023-08-19 15:20:23 +01:00
void CosCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-27 23:57:01 +02:00
{
2023-08-19 15:20:23 +01:00
m_value - > for_each_child_node ( callback ) ;
callback ( m_value ) ;
2023-05-27 23:57:01 +02:00
}
2023-08-22 14:13:22 +01:00
void CosCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-27 23:57:01 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}COS: {} \n " , " " , indent , to_string ( ) ) ;
2023-05-27 23:57:01 +02:00
}
2024-01-09 12:41:43 +01:00
bool CosCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_value - > equals ( * static_cast < CosCalculationNode const & > ( other ) . m_value ) ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < TanCalculationNode > TanCalculationNode : : create ( NonnullOwnPtr < CalculationNode > value )
2023-05-28 00:02:43 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) TanCalculationNode ( move ( value ) ) ) ;
2023-05-28 00:02:43 +02:00
}
TanCalculationNode : : TanCalculationNode ( NonnullOwnPtr < CalculationNode > value )
: CalculationNode ( Type : : Tan )
, m_value ( move ( value ) )
{
}
TanCalculationNode : : ~ TanCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String TanCalculationNode : : to_string ( ) const
2023-05-28 00:02:43 +02:00
{
StringBuilder builder ;
builder . append ( " tan( " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_value - > to_string ( ) ) ;
2023-05-28 00:02:43 +02:00
builder . append ( " ) " sv ) ;
2023-08-22 14:08:15 +01:00
return MUST ( builder . to_string ( ) ) ;
2023-05-28 00:02:43 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > TanCalculationNode : : resolved_type ( ) const
{
return CalculatedStyleValue : : ResolvedType : : Number ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > TanCalculationNode : : determine_type ( PropertyID ) const
{
// «[ ]» (empty map).
return CSSNumericType { } ;
}
2023-05-28 00:02:43 +02:00
bool TanCalculationNode : : contains_percentage ( ) const
{
return m_value - > contains_percentage ( ) ;
}
CalculatedStyleValue : : CalculationResult TanCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
auto node_a = m_value - > resolve ( context , percentage_basis ) ;
auto node_a_value = resolve_value_radians ( node_a . value ( ) ) ;
auto result = tan ( node_a_value ) ;
return { Number ( Number : : Type : : Number , result ) } ;
}
2023-08-19 15:20:23 +01:00
void TanCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-28 00:02:43 +02:00
{
2023-08-19 15:20:23 +01:00
m_value - > for_each_child_node ( callback ) ;
callback ( m_value ) ;
2023-05-28 00:02:43 +02:00
}
2023-08-22 14:13:22 +01:00
void TanCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-28 00:02:43 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}TAN: {} \n " , " " , indent , to_string ( ) ) ;
2023-05-28 00:02:43 +02:00
}
2024-01-09 12:41:43 +01:00
bool TanCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_value - > equals ( * static_cast < TanCalculationNode const & > ( other ) . m_value ) ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < AsinCalculationNode > AsinCalculationNode : : create ( NonnullOwnPtr < CalculationNode > value )
2023-05-28 10:55:52 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) AsinCalculationNode ( move ( value ) ) ) ;
2023-05-28 10:55:52 +02:00
}
AsinCalculationNode : : AsinCalculationNode ( NonnullOwnPtr < CalculationNode > value )
: CalculationNode ( Type : : Asin )
, m_value ( move ( value ) )
{
}
AsinCalculationNode : : ~ AsinCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String AsinCalculationNode : : to_string ( ) const
2023-05-28 10:55:52 +02:00
{
StringBuilder builder ;
builder . append ( " asin( " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_value - > to_string ( ) ) ;
2023-05-28 10:55:52 +02:00
builder . append ( " ) " sv ) ;
2023-08-22 14:08:15 +01:00
return MUST ( builder . to_string ( ) ) ;
2023-05-28 10:55:52 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > AsinCalculationNode : : resolved_type ( ) const
{
return CalculatedStyleValue : : ResolvedType : : Angle ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > AsinCalculationNode : : determine_type ( PropertyID ) const
{
2023-07-19 11:11:50 +01:00
// «[ "angle" → 1 ]».
2023-07-05 19:58:13 +01:00
return CSSNumericType { CSSNumericType : : BaseType : : Angle , 1 } ;
}
2023-05-28 10:55:52 +02:00
bool AsinCalculationNode : : contains_percentage ( ) const
{
return m_value - > contains_percentage ( ) ;
}
CalculatedStyleValue : : CalculationResult AsinCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
auto node_a = m_value - > resolve ( context , percentage_basis ) ;
auto node_a_value = resolve_value ( node_a . value ( ) , context ) ;
auto result = asin ( node_a_value ) ;
return { Angle ( result , Angle : : Type : : Rad ) } ;
}
2023-08-19 15:20:23 +01:00
void AsinCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-28 10:55:52 +02:00
{
2023-08-19 15:20:23 +01:00
m_value - > for_each_child_node ( callback ) ;
callback ( m_value ) ;
2023-05-28 10:55:52 +02:00
}
2023-08-22 14:13:22 +01:00
void AsinCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-28 10:55:52 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}ASIN: {} \n " , " " , indent , to_string ( ) ) ;
2023-05-28 10:55:52 +02:00
}
2024-01-09 12:41:43 +01:00
bool AsinCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_value - > equals ( * static_cast < AsinCalculationNode const & > ( other ) . m_value ) ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < AcosCalculationNode > AcosCalculationNode : : create ( NonnullOwnPtr < CalculationNode > value )
2023-05-28 11:00:35 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) AcosCalculationNode ( move ( value ) ) ) ;
2023-05-28 11:00:35 +02:00
}
AcosCalculationNode : : AcosCalculationNode ( NonnullOwnPtr < CalculationNode > value )
: CalculationNode ( Type : : Acos )
, m_value ( move ( value ) )
{
}
AcosCalculationNode : : ~ AcosCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String AcosCalculationNode : : to_string ( ) const
2023-05-28 11:00:35 +02:00
{
StringBuilder builder ;
builder . append ( " acos( " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_value - > to_string ( ) ) ;
2023-05-28 11:00:35 +02:00
builder . append ( " ) " sv ) ;
2023-08-22 14:08:15 +01:00
return MUST ( builder . to_string ( ) ) ;
2023-05-28 11:00:35 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > AcosCalculationNode : : resolved_type ( ) const
{
return CalculatedStyleValue : : ResolvedType : : Angle ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > AcosCalculationNode : : determine_type ( PropertyID ) const
{
2023-07-19 11:11:50 +01:00
// «[ "angle" → 1 ]».
2023-07-05 19:58:13 +01:00
return CSSNumericType { CSSNumericType : : BaseType : : Angle , 1 } ;
}
2023-05-28 11:00:35 +02:00
bool AcosCalculationNode : : contains_percentage ( ) const
{
return m_value - > contains_percentage ( ) ;
}
CalculatedStyleValue : : CalculationResult AcosCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
auto node_a = m_value - > resolve ( context , percentage_basis ) ;
auto node_a_value = resolve_value ( node_a . value ( ) , context ) ;
auto result = acos ( node_a_value ) ;
return { Angle ( result , Angle : : Type : : Rad ) } ;
}
2023-08-19 15:20:23 +01:00
void AcosCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-28 11:00:35 +02:00
{
2023-08-19 15:20:23 +01:00
m_value - > for_each_child_node ( callback ) ;
callback ( m_value ) ;
2023-05-28 11:00:35 +02:00
}
2023-08-22 14:13:22 +01:00
void AcosCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-28 11:00:35 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}ACOS: {} \n " , " " , indent , to_string ( ) ) ;
2023-05-28 11:00:35 +02:00
}
2024-01-09 12:41:43 +01:00
bool AcosCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_value - > equals ( * static_cast < AcosCalculationNode const & > ( other ) . m_value ) ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < AtanCalculationNode > AtanCalculationNode : : create ( NonnullOwnPtr < CalculationNode > value )
2023-05-28 11:04:57 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) AtanCalculationNode ( move ( value ) ) ) ;
2023-05-28 11:04:57 +02:00
}
AtanCalculationNode : : AtanCalculationNode ( NonnullOwnPtr < CalculationNode > value )
: CalculationNode ( Type : : Atan )
, m_value ( move ( value ) )
{
}
AtanCalculationNode : : ~ AtanCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String AtanCalculationNode : : to_string ( ) const
2023-05-28 11:04:57 +02:00
{
StringBuilder builder ;
builder . append ( " atan( " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_value - > to_string ( ) ) ;
2023-05-28 11:04:57 +02:00
builder . append ( " ) " sv ) ;
2023-08-22 14:08:15 +01:00
return MUST ( builder . to_string ( ) ) ;
2023-05-28 11:04:57 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > AtanCalculationNode : : resolved_type ( ) const
{
return CalculatedStyleValue : : ResolvedType : : Angle ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > AtanCalculationNode : : determine_type ( PropertyID ) const
{
2023-07-19 11:11:50 +01:00
// «[ "angle" → 1 ]».
2023-07-05 19:58:13 +01:00
return CSSNumericType { CSSNumericType : : BaseType : : Angle , 1 } ;
}
2023-05-28 11:04:57 +02:00
bool AtanCalculationNode : : contains_percentage ( ) const
{
return m_value - > contains_percentage ( ) ;
}
CalculatedStyleValue : : CalculationResult AtanCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
auto node_a = m_value - > resolve ( context , percentage_basis ) ;
auto node_a_value = resolve_value ( node_a . value ( ) , context ) ;
auto result = atan ( node_a_value ) ;
return { Angle ( result , Angle : : Type : : Rad ) } ;
}
2023-08-19 15:20:23 +01:00
void AtanCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-28 11:04:57 +02:00
{
2023-08-19 15:20:23 +01:00
m_value - > for_each_child_node ( callback ) ;
callback ( m_value ) ;
2023-05-28 11:04:57 +02:00
}
2023-08-22 14:13:22 +01:00
void AtanCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-28 11:04:57 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}ATAN: {} \n " , " " , indent , to_string ( ) ) ;
2023-05-28 11:04:57 +02:00
}
2024-01-09 12:41:43 +01:00
bool AtanCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_value - > equals ( * static_cast < AtanCalculationNode const & > ( other ) . m_value ) ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < Atan2CalculationNode > Atan2CalculationNode : : create ( NonnullOwnPtr < CalculationNode > y , NonnullOwnPtr < CalculationNode > x )
2023-05-28 11:19:10 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) Atan2CalculationNode ( move ( y ) , move ( x ) ) ) ;
2023-05-28 11:19:10 +02:00
}
Atan2CalculationNode : : Atan2CalculationNode ( NonnullOwnPtr < CalculationNode > y , NonnullOwnPtr < CalculationNode > x )
: CalculationNode ( Type : : Atan2 )
, m_y ( move ( y ) )
, m_x ( move ( x ) )
{
}
Atan2CalculationNode : : ~ Atan2CalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String Atan2CalculationNode : : to_string ( ) const
2023-05-28 11:19:10 +02:00
{
StringBuilder builder ;
builder . append ( " atan2( " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_y - > to_string ( ) ) ;
2023-05-28 11:19:10 +02:00
builder . append ( " , " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_x - > to_string ( ) ) ;
2023-05-28 11:19:10 +02:00
builder . append ( " ) " sv ) ;
2023-08-22 14:08:15 +01:00
return MUST ( builder . to_string ( ) ) ;
2023-05-28 11:19:10 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > Atan2CalculationNode : : resolved_type ( ) const
{
return CalculatedStyleValue : : ResolvedType : : Angle ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > Atan2CalculationNode : : determine_type ( PropertyID ) const
{
2023-07-19 11:11:50 +01:00
// «[ "angle" → 1 ]».
2023-07-05 19:58:13 +01:00
return CSSNumericType { CSSNumericType : : BaseType : : Angle , 1 } ;
}
2023-05-28 11:19:10 +02:00
bool Atan2CalculationNode : : contains_percentage ( ) const
{
return m_y - > contains_percentage ( ) | | m_x - > contains_percentage ( ) ;
}
CalculatedStyleValue : : CalculationResult Atan2CalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
auto node_a = m_y - > resolve ( context , percentage_basis ) ;
auto node_a_value = resolve_value ( node_a . value ( ) , context ) ;
auto node_b = m_x - > resolve ( context , percentage_basis ) ;
auto node_b_value = resolve_value ( node_b . value ( ) , context ) ;
auto result = atan2 ( node_a_value , node_b_value ) ;
return { Angle ( result , Angle : : Type : : Rad ) } ;
}
2023-08-19 15:20:23 +01:00
void Atan2CalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-28 11:19:10 +02:00
{
2023-08-19 15:20:23 +01:00
m_y - > for_each_child_node ( callback ) ;
m_x - > for_each_child_node ( callback ) ;
callback ( m_y ) ;
callback ( m_x ) ;
2023-05-28 11:19:10 +02:00
}
2023-08-22 14:13:22 +01:00
void Atan2CalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-28 11:19:10 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}ATAN2: {} \n " , " " , indent , to_string ( ) ) ;
2023-05-28 11:19:10 +02:00
}
2024-01-09 12:41:43 +01:00
bool Atan2CalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_x - > equals ( * static_cast < Atan2CalculationNode const & > ( other ) . m_x )
& & m_y - > equals ( * static_cast < Atan2CalculationNode const & > ( other ) . m_y ) ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < PowCalculationNode > PowCalculationNode : : create ( NonnullOwnPtr < CalculationNode > x , NonnullOwnPtr < CalculationNode > y )
2023-05-28 11:26:42 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) PowCalculationNode ( move ( x ) , move ( y ) ) ) ;
2023-05-28 11:26:42 +02:00
}
PowCalculationNode : : PowCalculationNode ( NonnullOwnPtr < CalculationNode > x , NonnullOwnPtr < CalculationNode > y )
: CalculationNode ( Type : : Pow )
, m_x ( move ( x ) )
, m_y ( move ( y ) )
{
}
PowCalculationNode : : ~ PowCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String PowCalculationNode : : to_string ( ) const
2023-05-28 11:26:42 +02:00
{
StringBuilder builder ;
builder . append ( " pow( " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_x - > to_string ( ) ) ;
2023-05-28 11:26:42 +02:00
builder . append ( " , " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_y - > to_string ( ) ) ;
2023-05-28 11:26:42 +02:00
builder . append ( " ) " sv ) ;
2023-08-22 14:08:15 +01:00
return MUST ( builder . to_string ( ) ) ;
2023-05-28 11:26:42 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > PowCalculationNode : : resolved_type ( ) const
{
return CalculatedStyleValue : : ResolvedType : : Number ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > PowCalculationNode : : determine_type ( PropertyID ) const
{
// «[ ]» (empty map).
return CSSNumericType { } ;
}
2023-05-28 11:26:42 +02:00
CalculatedStyleValue : : CalculationResult PowCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
auto node_a = m_x - > resolve ( context , percentage_basis ) ;
auto node_a_value = resolve_value ( node_a . value ( ) , context ) ;
auto node_b = m_y - > resolve ( context , percentage_basis ) ;
auto node_b_value = resolve_value ( node_b . value ( ) , context ) ;
auto result = pow ( node_a_value , node_b_value ) ;
return { Number ( Number : : Type : : Number , result ) } ;
}
2023-08-19 15:20:23 +01:00
void PowCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-28 11:26:42 +02:00
{
2023-08-19 15:20:23 +01:00
m_x - > for_each_child_node ( callback ) ;
m_y - > for_each_child_node ( callback ) ;
callback ( m_x ) ;
callback ( m_y ) ;
2023-05-28 11:26:42 +02:00
}
2023-08-22 14:13:22 +01:00
void PowCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-28 11:26:42 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}POW: {} \n " , " " , indent , to_string ( ) ) ;
2023-05-28 11:26:42 +02:00
}
2024-01-09 12:41:43 +01:00
bool PowCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_x - > equals ( * static_cast < PowCalculationNode const & > ( other ) . m_x )
& & m_y - > equals ( * static_cast < PowCalculationNode const & > ( other ) . m_y ) ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < SqrtCalculationNode > SqrtCalculationNode : : create ( NonnullOwnPtr < CalculationNode > value )
2023-05-28 11:31:50 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) SqrtCalculationNode ( move ( value ) ) ) ;
2023-05-28 11:31:50 +02:00
}
SqrtCalculationNode : : SqrtCalculationNode ( NonnullOwnPtr < CalculationNode > value )
: CalculationNode ( Type : : Sqrt )
, m_value ( move ( value ) )
{
}
SqrtCalculationNode : : ~ SqrtCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String SqrtCalculationNode : : to_string ( ) const
2023-05-28 11:31:50 +02:00
{
StringBuilder builder ;
builder . append ( " sqrt( " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_value - > to_string ( ) ) ;
2023-05-28 11:31:50 +02:00
builder . append ( " ) " sv ) ;
2023-08-22 14:08:15 +01:00
return MUST ( builder . to_string ( ) ) ;
2023-05-28 11:31:50 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > SqrtCalculationNode : : resolved_type ( ) const
{
return CalculatedStyleValue : : ResolvedType : : Number ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > SqrtCalculationNode : : determine_type ( PropertyID ) const
{
// «[ ]» (empty map).
return CSSNumericType { } ;
}
2023-05-28 11:31:50 +02:00
CalculatedStyleValue : : CalculationResult SqrtCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
auto node_a = m_value - > resolve ( context , percentage_basis ) ;
auto node_a_value = resolve_value ( node_a . value ( ) , context ) ;
auto result = sqrt ( node_a_value ) ;
return { Number ( Number : : Type : : Number , result ) } ;
}
2023-08-19 15:20:23 +01:00
void SqrtCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-28 11:31:50 +02:00
{
2023-08-19 15:20:23 +01:00
m_value - > for_each_child_node ( callback ) ;
callback ( m_value ) ;
2023-05-28 11:31:50 +02:00
}
2023-08-22 14:13:22 +01:00
void SqrtCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-28 11:31:50 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}SQRT: {} \n " , " " , indent , to_string ( ) ) ;
2023-05-28 11:31:50 +02:00
}
2024-01-09 12:41:43 +01:00
bool SqrtCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_value - > equals ( * static_cast < SqrtCalculationNode const & > ( other ) . m_value ) ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < HypotCalculationNode > HypotCalculationNode : : create ( Vector < NonnullOwnPtr < Web : : CSS : : CalculationNode > > values )
2023-05-28 11:43:04 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) HypotCalculationNode ( move ( values ) ) ) ;
2023-05-28 11:43:04 +02:00
}
HypotCalculationNode : : HypotCalculationNode ( Vector < NonnullOwnPtr < CalculationNode > > values )
: CalculationNode ( Type : : Hypot )
, m_values ( move ( values ) )
{
}
HypotCalculationNode : : ~ HypotCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String HypotCalculationNode : : to_string ( ) const
2023-05-28 11:43:04 +02:00
{
StringBuilder builder ;
2023-08-22 14:08:15 +01:00
builder . append ( " hypot( " sv ) ;
2023-05-28 11:43:04 +02:00
for ( size_t i = 0 ; i < m_values . size ( ) ; + + i ) {
if ( i ! = 0 )
2023-08-22 14:08:15 +01:00
builder . append ( " , " sv ) ;
builder . append ( m_values [ i ] - > to_string ( ) ) ;
2023-05-28 11:43:04 +02:00
}
2023-08-22 14:08:15 +01:00
builder . append ( " ) " sv ) ;
return MUST ( builder . to_string ( ) ) ;
2023-05-28 11:43:04 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > HypotCalculationNode : : resolved_type ( ) const
{
// NOTE: We check during parsing that all values have the same type.
return m_values [ 0 ] - > resolved_type ( ) ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > HypotCalculationNode : : determine_type ( PropertyID property_id ) const
{
// The result of adding the types of its comma-separated calculations.
return add_the_types ( m_values , property_id ) ;
}
2023-05-28 11:43:04 +02:00
bool HypotCalculationNode : : contains_percentage ( ) const
{
for ( auto const & value : m_values ) {
if ( value - > contains_percentage ( ) )
return true ;
}
return false ;
}
CalculatedStyleValue : : CalculationResult HypotCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
double square_sum = 0.0 ;
for ( auto const & value : m_values ) {
auto child_resolved = value - > resolve ( context , percentage_basis ) ;
auto child_value = resolve_value ( child_resolved . value ( ) , context ) ;
square_sum + = child_value * child_value ;
}
auto result = sqrt ( square_sum ) ;
return to_resolved_type ( resolved_type ( ) . value ( ) , result ) ;
}
2023-08-19 15:20:23 +01:00
void HypotCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-28 11:43:04 +02:00
{
for ( auto & value : m_values ) {
2023-08-19 15:20:23 +01:00
value - > for_each_child_node ( callback ) ;
callback ( value ) ;
2023-05-28 11:43:04 +02:00
}
}
2023-08-22 14:13:22 +01:00
void HypotCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-28 11:43:04 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}HYPOT: \n " , " " , indent ) ;
2023-05-28 11:43:04 +02:00
for ( auto const & value : m_values )
2023-08-22 14:13:22 +01:00
value - > dump ( builder , indent + 2 ) ;
2023-05-28 11:43:04 +02:00
}
2024-01-09 12:41:43 +01:00
bool HypotCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
for ( size_t i = 0 ; i < m_values . size ( ) ; + + i ) {
if ( ! m_values [ i ] - > equals ( * static_cast < HypotCalculationNode const & > ( other ) . m_values [ i ] ) )
return false ;
}
return true ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < LogCalculationNode > LogCalculationNode : : create ( NonnullOwnPtr < CalculationNode > x , NonnullOwnPtr < CalculationNode > y )
2023-05-28 11:53:57 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) LogCalculationNode ( move ( x ) , move ( y ) ) ) ;
2023-05-28 11:53:57 +02:00
}
LogCalculationNode : : LogCalculationNode ( NonnullOwnPtr < CalculationNode > x , NonnullOwnPtr < CalculationNode > y )
: CalculationNode ( Type : : Log )
, m_x ( move ( x ) )
, m_y ( move ( y ) )
{
}
LogCalculationNode : : ~ LogCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String LogCalculationNode : : to_string ( ) const
2023-05-28 11:53:57 +02:00
{
StringBuilder builder ;
builder . append ( " log( " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_x - > to_string ( ) ) ;
2023-05-28 11:53:57 +02:00
builder . append ( " , " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_y - > to_string ( ) ) ;
2023-05-28 11:53:57 +02:00
builder . append ( " ) " sv ) ;
2023-08-22 14:08:15 +01:00
return MUST ( builder . to_string ( ) ) ;
2023-05-28 11:53:57 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > LogCalculationNode : : resolved_type ( ) const
{
return CalculatedStyleValue : : ResolvedType : : Number ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > LogCalculationNode : : determine_type ( PropertyID ) const
{
// «[ ]» (empty map).
return CSSNumericType { } ;
}
2023-05-28 11:53:57 +02:00
CalculatedStyleValue : : CalculationResult LogCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
auto node_a = m_x - > resolve ( context , percentage_basis ) ;
auto node_a_value = resolve_value ( node_a . value ( ) , context ) ;
auto node_b = m_y - > resolve ( context , percentage_basis ) ;
auto node_b_value = resolve_value ( node_b . value ( ) , context ) ;
auto result = log2 ( node_a_value ) / log2 ( node_b_value ) ;
return { Number ( Number : : Type : : Number , result ) } ;
}
2023-08-19 15:20:23 +01:00
void LogCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-28 11:53:57 +02:00
{
2023-08-19 15:20:23 +01:00
m_x - > for_each_child_node ( callback ) ;
m_y - > for_each_child_node ( callback ) ;
callback ( m_x ) ;
callback ( m_y ) ;
2023-05-28 11:53:57 +02:00
}
2023-08-22 14:13:22 +01:00
void LogCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-28 11:53:57 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}LOG: {} \n " , " " , indent , to_string ( ) ) ;
2023-05-28 11:53:57 +02:00
}
2024-01-09 12:41:43 +01:00
bool LogCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_x - > equals ( * static_cast < LogCalculationNode const & > ( other ) . m_x )
& & m_y - > equals ( * static_cast < LogCalculationNode const & > ( other ) . m_y ) ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < ExpCalculationNode > ExpCalculationNode : : create ( NonnullOwnPtr < CalculationNode > value )
2023-05-28 11:58:30 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) ExpCalculationNode ( move ( value ) ) ) ;
2023-05-28 11:58:30 +02:00
}
ExpCalculationNode : : ExpCalculationNode ( NonnullOwnPtr < CalculationNode > value )
: CalculationNode ( Type : : Exp )
, m_value ( move ( value ) )
{
}
ExpCalculationNode : : ~ ExpCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String ExpCalculationNode : : to_string ( ) const
2023-05-28 11:58:30 +02:00
{
StringBuilder builder ;
builder . append ( " exp( " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_value - > to_string ( ) ) ;
2023-05-28 11:58:30 +02:00
builder . append ( " ) " sv ) ;
2023-08-22 14:08:15 +01:00
return MUST ( builder . to_string ( ) ) ;
2023-05-28 11:58:30 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > ExpCalculationNode : : resolved_type ( ) const
{
return CalculatedStyleValue : : ResolvedType : : Number ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > ExpCalculationNode : : determine_type ( PropertyID ) const
{
// «[ ]» (empty map).
return CSSNumericType { } ;
}
2023-05-28 11:58:30 +02:00
CalculatedStyleValue : : CalculationResult ExpCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
auto node_a = m_value - > resolve ( context , percentage_basis ) ;
auto node_a_value = resolve_value ( node_a . value ( ) , context ) ;
auto result = exp ( node_a_value ) ;
return { Number ( Number : : Type : : Number , result ) } ;
}
2023-08-19 15:20:23 +01:00
void ExpCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-28 11:58:30 +02:00
{
2023-08-19 15:20:23 +01:00
m_value - > for_each_child_node ( callback ) ;
callback ( m_value ) ;
2023-05-28 11:58:30 +02:00
}
2023-08-22 14:13:22 +01:00
void ExpCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-28 11:58:30 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}EXP: {} \n " , " " , indent , to_string ( ) ) ;
2023-05-28 11:58:30 +02:00
}
2024-01-09 12:41:43 +01:00
bool ExpCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_value - > equals ( * static_cast < ExpCalculationNode const & > ( other ) . m_value ) ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < RoundCalculationNode > RoundCalculationNode : : create ( RoundingStrategy strategy , NonnullOwnPtr < CalculationNode > x , NonnullOwnPtr < CalculationNode > y )
2023-05-27 16:07:50 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) RoundCalculationNode ( strategy , move ( x ) , move ( y ) ) ) ;
2023-05-27 16:07:50 +02:00
}
2023-07-13 14:51:11 +01:00
RoundCalculationNode : : RoundCalculationNode ( RoundingStrategy mode , NonnullOwnPtr < CalculationNode > x , NonnullOwnPtr < CalculationNode > y )
2023-05-27 16:07:50 +02:00
: CalculationNode ( Type : : Round )
2023-07-13 14:51:11 +01:00
, m_strategy ( mode )
2023-05-27 16:07:50 +02:00
, m_x ( move ( x ) )
, m_y ( move ( y ) )
{
}
RoundCalculationNode : : ~ RoundCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String RoundCalculationNode : : to_string ( ) const
2023-05-27 16:07:50 +02:00
{
StringBuilder builder ;
builder . append ( " round( " sv ) ;
2023-07-13 14:51:11 +01:00
builder . append ( CSS : : to_string ( m_strategy ) ) ;
2023-05-27 16:07:50 +02:00
builder . append ( " , " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_x - > to_string ( ) ) ;
2023-05-27 16:07:50 +02:00
builder . append ( " , " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_y - > to_string ( ) ) ;
2023-05-27 16:07:50 +02:00
builder . append ( " ) " sv ) ;
2023-08-22 14:08:15 +01:00
return MUST ( builder . to_string ( ) ) ;
2023-05-27 16:07:50 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > RoundCalculationNode : : resolved_type ( ) const
{
// Note: We check during parsing that all values have the same type
return m_x - > resolved_type ( ) ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > RoundCalculationNode : : determine_type ( PropertyID property_id ) const
{
// The result of adding the types of its comma-separated calculations.
auto x_type = m_x - > determine_type ( property_id ) ;
auto y_type = m_y - > determine_type ( property_id ) ;
if ( ! x_type . has_value ( ) | | ! y_type . has_value ( ) )
return { } ;
return x_type - > added_to ( * y_type ) ;
}
2023-05-27 16:07:50 +02:00
bool RoundCalculationNode : : contains_percentage ( ) const
{
return m_x - > contains_percentage ( ) | | m_y - > contains_percentage ( ) ;
}
CalculatedStyleValue : : CalculationResult RoundCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
auto resolved_type = m_x - > resolved_type ( ) . value ( ) ;
auto node_a = m_x - > resolve ( context , percentage_basis ) ;
auto node_b = m_y - > resolve ( context , percentage_basis ) ;
auto node_a_value = resolve_value ( node_a . value ( ) , context ) ;
auto node_b_value = resolve_value ( node_b . value ( ) , context ) ;
auto upper_b = ceil ( node_a_value / node_b_value ) * node_b_value ;
auto lower_b = floor ( node_a_value / node_b_value ) * node_b_value ;
2023-07-13 14:51:11 +01:00
if ( m_strategy = = RoundingStrategy : : Nearest ) {
2023-05-27 16:07:50 +02:00
auto upper_diff = fabs ( upper_b - node_a_value ) ;
auto lower_diff = fabs ( node_a_value - lower_b ) ;
auto rounded_value = upper_diff < lower_diff ? upper_b : lower_b ;
return to_resolved_type ( resolved_type , rounded_value ) ;
}
2023-07-13 14:51:11 +01:00
if ( m_strategy = = RoundingStrategy : : Up ) {
2023-05-27 16:07:50 +02:00
return to_resolved_type ( resolved_type , upper_b ) ;
}
2023-07-13 14:51:11 +01:00
if ( m_strategy = = RoundingStrategy : : Down ) {
2023-05-27 16:07:50 +02:00
return to_resolved_type ( resolved_type , lower_b ) ;
}
2023-07-13 14:51:11 +01:00
if ( m_strategy = = RoundingStrategy : : ToZero ) {
2023-05-27 16:07:50 +02:00
auto upper_diff = fabs ( upper_b ) ;
auto lower_diff = fabs ( lower_b ) ;
auto rounded_value = upper_diff < lower_diff ? upper_b : lower_b ;
return to_resolved_type ( resolved_type , rounded_value ) ;
}
VERIFY_NOT_REACHED ( ) ;
}
2023-08-19 15:20:23 +01:00
void RoundCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-27 16:07:50 +02:00
{
2023-08-19 15:20:23 +01:00
m_x - > for_each_child_node ( callback ) ;
m_y - > for_each_child_node ( callback ) ;
callback ( m_x ) ;
callback ( m_y ) ;
2023-05-27 16:07:50 +02:00
}
2023-08-22 14:13:22 +01:00
void RoundCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-27 16:07:50 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}ROUND: {} \n " , " " , indent , to_string ( ) ) ;
2023-05-27 16:07:50 +02:00
}
2024-01-09 12:41:43 +01:00
bool RoundCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_strategy = = static_cast < RoundCalculationNode const & > ( other ) . m_strategy
& & m_x - > equals ( * static_cast < RoundCalculationNode const & > ( other ) . m_x )
& & m_y - > equals ( * static_cast < RoundCalculationNode const & > ( other ) . m_y ) ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < ModCalculationNode > ModCalculationNode : : create ( NonnullOwnPtr < CalculationNode > x , NonnullOwnPtr < CalculationNode > y )
2023-05-27 19:03:07 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) ModCalculationNode ( move ( x ) , move ( y ) ) ) ;
2023-05-27 19:03:07 +02:00
}
ModCalculationNode : : ModCalculationNode ( NonnullOwnPtr < CalculationNode > x , NonnullOwnPtr < CalculationNode > y )
: CalculationNode ( Type : : Mod )
, m_x ( move ( x ) )
, m_y ( move ( y ) )
{
}
ModCalculationNode : : ~ ModCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String ModCalculationNode : : to_string ( ) const
2023-05-27 19:03:07 +02:00
{
StringBuilder builder ;
builder . append ( " mod( " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_x - > to_string ( ) ) ;
2023-05-27 19:03:07 +02:00
builder . append ( " , " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_y - > to_string ( ) ) ;
2023-05-27 19:03:07 +02:00
builder . append ( " ) " sv ) ;
2023-08-22 14:08:15 +01:00
return MUST ( builder . to_string ( ) ) ;
2023-05-27 19:03:07 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > ModCalculationNode : : resolved_type ( ) const
{
// Note: We check during parsing that all values have the same type
return m_x - > resolved_type ( ) ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > ModCalculationNode : : determine_type ( PropertyID property_id ) const
{
// The result of adding the types of its comma-separated calculations.
auto x_type = m_x - > determine_type ( property_id ) ;
auto y_type = m_y - > determine_type ( property_id ) ;
if ( ! x_type . has_value ( ) | | ! y_type . has_value ( ) )
return { } ;
return x_type - > added_to ( * y_type ) ;
}
2023-05-27 19:03:07 +02:00
bool ModCalculationNode : : contains_percentage ( ) const
{
return m_x - > contains_percentage ( ) | | m_y - > contains_percentage ( ) ;
}
CalculatedStyleValue : : CalculationResult ModCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
auto resolved_type = m_x - > resolved_type ( ) . value ( ) ;
auto node_a = m_x - > resolve ( context , percentage_basis ) ;
auto node_b = m_y - > resolve ( context , percentage_basis ) ;
auto node_a_value = resolve_value ( node_a . value ( ) , context ) ;
auto node_b_value = resolve_value ( node_b . value ( ) , context ) ;
auto quotient = floor ( node_a_value / node_b_value ) ;
auto value = node_a_value - ( node_b_value * quotient ) ;
return to_resolved_type ( resolved_type , value ) ;
}
2023-08-19 15:20:23 +01:00
void ModCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-27 19:03:07 +02:00
{
2023-08-19 15:20:23 +01:00
m_x - > for_each_child_node ( callback ) ;
m_y - > for_each_child_node ( callback ) ;
callback ( m_x ) ;
callback ( m_y ) ;
2023-05-27 19:03:07 +02:00
}
2023-08-22 14:13:22 +01:00
void ModCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-27 19:03:07 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}MOD: {} \n " , " " , indent , to_string ( ) ) ;
2023-05-27 19:03:07 +02:00
}
2024-01-09 12:41:43 +01:00
bool ModCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_x - > equals ( * static_cast < ModCalculationNode const & > ( other ) . m_x )
& & m_y - > equals ( * static_cast < ModCalculationNode const & > ( other ) . m_y ) ;
}
2023-08-19 15:20:23 +01:00
NonnullOwnPtr < RemCalculationNode > RemCalculationNode : : create ( NonnullOwnPtr < CalculationNode > x , NonnullOwnPtr < CalculationNode > y )
2023-05-27 19:08:07 +02:00
{
2023-08-19 15:20:23 +01:00
return adopt_own ( * new ( nothrow ) RemCalculationNode ( move ( x ) , move ( y ) ) ) ;
2023-05-27 19:08:07 +02:00
}
RemCalculationNode : : RemCalculationNode ( NonnullOwnPtr < CalculationNode > x , NonnullOwnPtr < CalculationNode > y )
: CalculationNode ( Type : : Rem )
, m_x ( move ( x ) )
, m_y ( move ( y ) )
{
}
RemCalculationNode : : ~ RemCalculationNode ( ) = default ;
2023-08-22 14:08:15 +01:00
String RemCalculationNode : : to_string ( ) const
2023-05-27 19:08:07 +02:00
{
StringBuilder builder ;
builder . append ( " rem( " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_x - > to_string ( ) ) ;
2023-05-27 19:08:07 +02:00
builder . append ( " , " sv ) ;
2023-08-22 14:08:15 +01:00
builder . append ( m_y - > to_string ( ) ) ;
2023-05-27 19:08:07 +02:00
builder . append ( " ) " sv ) ;
2023-08-22 14:08:15 +01:00
return MUST ( builder . to_string ( ) ) ;
2023-05-27 19:08:07 +02:00
}
Optional < CalculatedStyleValue : : ResolvedType > RemCalculationNode : : resolved_type ( ) const
{
// Note: We check during parsing that all values have the same type
return m_x - > resolved_type ( ) ;
}
2023-07-05 19:58:13 +01:00
// https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
Optional < CSSNumericType > RemCalculationNode : : determine_type ( PropertyID property_id ) const
{
// The result of adding the types of its comma-separated calculations.
auto x_type = m_x - > determine_type ( property_id ) ;
auto y_type = m_y - > determine_type ( property_id ) ;
if ( ! x_type . has_value ( ) | | ! y_type . has_value ( ) )
return { } ;
return x_type - > added_to ( * y_type ) ;
}
2023-05-27 19:08:07 +02:00
bool RemCalculationNode : : contains_percentage ( ) const
{
return m_x - > contains_percentage ( ) | | m_y - > contains_percentage ( ) ;
}
CalculatedStyleValue : : CalculationResult RemCalculationNode : : resolve ( Optional < Length : : ResolutionContext const & > context , CalculatedStyleValue : : PercentageBasis const & percentage_basis ) const
{
auto resolved_type = m_x - > resolved_type ( ) . value ( ) ;
auto node_a = m_x - > resolve ( context , percentage_basis ) ;
auto node_b = m_y - > resolve ( context , percentage_basis ) ;
auto node_a_value = resolve_value ( node_a . value ( ) , context ) ;
auto node_b_value = resolve_value ( node_b . value ( ) , context ) ;
auto value = fmod ( node_a_value , node_b_value ) ;
return to_resolved_type ( resolved_type , value ) ;
}
2023-08-19 15:20:23 +01:00
void RemCalculationNode : : for_each_child_node ( Function < void ( NonnullOwnPtr < CalculationNode > & ) > const & callback )
2023-05-27 19:08:07 +02:00
{
2023-08-19 15:20:23 +01:00
m_x - > for_each_child_node ( callback ) ;
m_y - > for_each_child_node ( callback ) ;
callback ( m_x ) ;
callback ( m_y ) ;
2023-05-27 19:08:07 +02:00
}
2023-08-22 14:13:22 +01:00
void RemCalculationNode : : dump ( StringBuilder & builder , int indent ) const
2023-05-27 19:08:07 +02:00
{
2023-08-22 14:08:15 +01:00
builder . appendff ( " {: >{}}REM: {} \n " , " " , indent , to_string ( ) ) ;
2023-05-27 19:08:07 +02:00
}
2024-01-09 12:41:43 +01:00
bool RemCalculationNode : : equals ( CalculationNode const & other ) const
{
if ( this = = & other )
return true ;
if ( type ( ) ! = other . type ( ) )
return false ;
return m_x - > equals ( * static_cast < RemCalculationNode const & > ( other ) . m_x )
& & m_y - > equals ( * static_cast < RemCalculationNode const & > ( other ) . m_y ) ;
}
2023-06-02 12:39:39 +02:00
void CalculatedStyleValue : : CalculationResult : : add ( CalculationResult const & other , Optional < Length : : ResolutionContext const & > context , PercentageBasis const & percentage_basis )
2023-03-30 17:34:14 +01:00
{
2023-06-02 12:39:39 +02:00
add_or_subtract_internal ( SumOperation : : Add , other , context , percentage_basis ) ;
2023-03-30 17:34:14 +01:00
}
2023-06-02 12:39:39 +02:00
void CalculatedStyleValue : : CalculationResult : : subtract ( CalculationResult const & other , Optional < Length : : ResolutionContext const & > context , PercentageBasis const & percentage_basis )
2023-03-30 17:34:14 +01:00
{
2023-06-02 12:39:39 +02:00
add_or_subtract_internal ( SumOperation : : Subtract , other , context , percentage_basis ) ;
2023-03-30 17:34:14 +01:00
}
2023-06-02 12:39:39 +02:00
void CalculatedStyleValue : : CalculationResult : : add_or_subtract_internal ( SumOperation op , CalculationResult const & other , Optional < Length : : ResolutionContext const & > context , PercentageBasis const & percentage_basis )
2023-03-30 17:34:14 +01:00
{
// We know from validation when resolving the type, that "both sides have the same type, or that one side is a <number> and the other is an <integer>".
// Though, having the same type may mean that one side is a <dimension> and the other a <percentage>.
// Note: This is almost identical to ::add()
m_value . visit (
[ & ] ( Number const & number ) {
auto other_number = other . m_value . get < Number > ( ) ;
if ( op = = SumOperation : : Add ) {
m_value = number + other_number ;
} else {
m_value = number - other_number ;
}
} ,
[ & ] ( Angle const & angle ) {
auto this_degrees = angle . to_degrees ( ) ;
if ( other . m_value . has < Angle > ( ) ) {
auto other_degrees = other . m_value . get < Angle > ( ) . to_degrees ( ) ;
if ( op = = SumOperation : : Add )
m_value = Angle : : make_degrees ( this_degrees + other_degrees ) ;
else
m_value = Angle : : make_degrees ( this_degrees - other_degrees ) ;
} else {
VERIFY ( percentage_basis . has < Angle > ( ) ) ;
auto other_degrees = percentage_basis . get < Angle > ( ) . percentage_of ( other . m_value . get < Percentage > ( ) ) . to_degrees ( ) ;
if ( op = = SumOperation : : Add )
m_value = Angle : : make_degrees ( this_degrees + other_degrees ) ;
else
m_value = Angle : : make_degrees ( this_degrees - other_degrees ) ;
}
} ,
2023-09-28 15:18:14 +01:00
[ & ] ( Flex const & flex ) {
auto this_fr = flex . to_fr ( ) ;
if ( other . m_value . has < Flex > ( ) ) {
auto other_fr = other . m_value . get < Flex > ( ) . to_fr ( ) ;
if ( op = = SumOperation : : Add )
m_value = Flex : : make_fr ( this_fr + other_fr ) ;
else
m_value = Flex : : make_fr ( this_fr - other_fr ) ;
} else {
VERIFY ( percentage_basis . has < Flex > ( ) ) ;
auto other_fr = percentage_basis . get < Flex > ( ) . percentage_of ( other . m_value . get < Percentage > ( ) ) . to_fr ( ) ;
if ( op = = SumOperation : : Add )
m_value = Flex : : make_fr ( this_fr + other_fr ) ;
else
m_value = Flex : : make_fr ( this_fr - other_fr ) ;
}
} ,
2023-03-30 17:34:14 +01:00
[ & ] ( Frequency const & frequency ) {
auto this_hertz = frequency . to_hertz ( ) ;
if ( other . m_value . has < Frequency > ( ) ) {
auto other_hertz = other . m_value . get < Frequency > ( ) . to_hertz ( ) ;
if ( op = = SumOperation : : Add )
m_value = Frequency : : make_hertz ( this_hertz + other_hertz ) ;
else
m_value = Frequency : : make_hertz ( this_hertz - other_hertz ) ;
} else {
VERIFY ( percentage_basis . has < Frequency > ( ) ) ;
auto other_hertz = percentage_basis . get < Frequency > ( ) . percentage_of ( other . m_value . get < Percentage > ( ) ) . to_hertz ( ) ;
if ( op = = SumOperation : : Add )
m_value = Frequency : : make_hertz ( this_hertz + other_hertz ) ;
else
m_value = Frequency : : make_hertz ( this_hertz - other_hertz ) ;
}
} ,
[ & ] ( Length const & length ) {
2023-06-02 12:39:39 +02:00
auto this_px = length . to_px ( * context ) ;
2023-03-30 17:34:14 +01:00
if ( other . m_value . has < Length > ( ) ) {
2023-06-02 12:39:39 +02:00
auto other_px = other . m_value . get < Length > ( ) . to_px ( * context ) ;
2023-03-30 17:34:14 +01:00
if ( op = = SumOperation : : Add )
m_value = Length : : make_px ( this_px + other_px ) ;
else
m_value = Length : : make_px ( this_px - other_px ) ;
} else {
VERIFY ( percentage_basis . has < Length > ( ) ) ;
2023-06-02 12:39:39 +02:00
auto other_px = percentage_basis . get < Length > ( ) . percentage_of ( other . m_value . get < Percentage > ( ) ) . to_px ( * context ) ;
2023-03-30 17:34:14 +01:00
if ( op = = SumOperation : : Add )
m_value = Length : : make_px ( this_px + other_px ) ;
else
m_value = Length : : make_px ( this_px - other_px ) ;
}
} ,
2023-12-30 17:05:23 +00:00
[ & ] ( Resolution const & resolution ) {
auto this_dots_per_pixel = resolution . to_dots_per_pixel ( ) ;
// NOTE: <resolution-percentage> is not a type, so we don't have to worry about percentages.
auto other_dots_per_pixel = other . m_value . get < Resolution > ( ) . to_dots_per_pixel ( ) ;
if ( op = = SumOperation : : Add )
m_value = Resolution : : make_dots_per_pixel ( this_dots_per_pixel + other_dots_per_pixel ) ;
else
m_value = Resolution : : make_dots_per_pixel ( this_dots_per_pixel - other_dots_per_pixel ) ;
} ,
2023-03-30 17:34:14 +01:00
[ & ] ( Time const & time ) {
auto this_seconds = time . to_seconds ( ) ;
if ( other . m_value . has < Time > ( ) ) {
auto other_seconds = other . m_value . get < Time > ( ) . to_seconds ( ) ;
if ( op = = SumOperation : : Add )
m_value = Time : : make_seconds ( this_seconds + other_seconds ) ;
else
m_value = Time : : make_seconds ( this_seconds - other_seconds ) ;
} else {
VERIFY ( percentage_basis . has < Time > ( ) ) ;
auto other_seconds = percentage_basis . get < Time > ( ) . percentage_of ( other . m_value . get < Percentage > ( ) ) . to_seconds ( ) ;
if ( op = = SumOperation : : Add )
m_value = Time : : make_seconds ( this_seconds + other_seconds ) ;
else
m_value = Time : : make_seconds ( this_seconds - other_seconds ) ;
}
} ,
[ & ] ( Percentage const & percentage ) {
if ( other . m_value . has < Percentage > ( ) ) {
if ( op = = SumOperation : : Add )
m_value = Percentage { percentage . value ( ) + other . m_value . get < Percentage > ( ) . value ( ) } ;
else
m_value = Percentage { percentage . value ( ) - other . m_value . get < Percentage > ( ) . value ( ) } ;
return ;
}
// Other side isn't a percentage, so the easiest way to handle it without duplicating all the logic, is just to swap `this` and `other`.
CalculationResult new_value = other ;
if ( op = = SumOperation : : Add ) {
2023-06-02 12:39:39 +02:00
new_value . add ( * this , context , percentage_basis ) ;
2023-03-30 17:34:14 +01:00
} else {
// Turn 'this - other' into '-other + this', as 'A + B == B + A', but 'A - B != B - A'
2023-06-02 12:39:39 +02:00
new_value . multiply_by ( { Number { Number : : Type : : Integer , - 1.0f } } , context ) ;
new_value . add ( * this , context , percentage_basis ) ;
2023-03-30 17:34:14 +01:00
}
* this = new_value ;
} ) ;
}
2023-06-02 12:39:39 +02:00
void CalculatedStyleValue : : CalculationResult : : multiply_by ( CalculationResult const & other , Optional < Length : : ResolutionContext const & > context )
2023-03-30 17:34:14 +01:00
{
// We know from validation when resolving the type, that at least one side must be a <number> or <integer>.
2023-05-27 21:10:21 +02:00
// Both of these are represented as a double.
2023-03-30 17:34:14 +01:00
VERIFY ( m_value . has < Number > ( ) | | other . m_value . has < Number > ( ) ) ;
bool other_is_number = other . m_value . has < Number > ( ) ;
m_value . visit (
[ & ] ( Number const & number ) {
if ( other_is_number ) {
m_value = number * other . m_value . get < Number > ( ) ;
} else {
// Avoid duplicating all the logic by swapping `this` and `other`.
CalculationResult new_value = other ;
2023-06-02 12:39:39 +02:00
new_value . multiply_by ( * this , context ) ;
2023-03-30 17:34:14 +01:00
* this = new_value ;
}
} ,
[ & ] ( Angle const & angle ) {
m_value = Angle : : make_degrees ( angle . to_degrees ( ) * other . m_value . get < Number > ( ) . value ( ) ) ;
} ,
2023-09-28 15:18:14 +01:00
[ & ] ( Flex const & flex ) {
m_value = Flex : : make_fr ( flex . to_fr ( ) * other . m_value . get < Number > ( ) . value ( ) ) ;
} ,
2023-03-30 17:34:14 +01:00
[ & ] ( Frequency const & frequency ) {
m_value = Frequency : : make_hertz ( frequency . to_hertz ( ) * other . m_value . get < Number > ( ) . value ( ) ) ;
} ,
[ & ] ( Length const & length ) {
2023-08-26 15:57:31 +01:00
m_value = Length : : make_px ( CSSPixels : : nearest_value_for ( length . to_px ( * context ) * static_cast < double > ( other . m_value . get < Number > ( ) . value ( ) ) ) ) ;
2023-03-30 17:34:14 +01:00
} ,
2023-12-30 17:05:23 +00:00
[ & ] ( Resolution const & resolution ) {
m_value = Resolution : : make_dots_per_pixel ( resolution . to_dots_per_pixel ( ) * other . m_value . get < Number > ( ) . value ( ) ) ;
} ,
2023-03-30 17:34:14 +01:00
[ & ] ( Time const & time ) {
m_value = Time : : make_seconds ( time . to_seconds ( ) * other . m_value . get < Number > ( ) . value ( ) ) ;
} ,
[ & ] ( Percentage const & percentage ) {
m_value = Percentage { percentage . value ( ) * other . m_value . get < Number > ( ) . value ( ) } ;
} ) ;
}
2023-06-02 12:39:39 +02:00
void CalculatedStyleValue : : CalculationResult : : divide_by ( CalculationResult const & other , Optional < Length : : ResolutionContext const & > context )
2023-03-30 17:34:14 +01:00
{
// We know from validation when resolving the type, that `other` must be a <number> or <integer>.
// Both of these are represented as a Number.
auto denominator = other . m_value . get < Number > ( ) . value ( ) ;
// FIXME: Dividing by 0 is invalid, and should be caught during parsing.
2023-05-27 21:10:21 +02:00
VERIFY ( denominator ! = 0.0 ) ;
2023-03-30 17:34:14 +01:00
m_value . visit (
[ & ] ( Number const & number ) {
m_value = Number {
Number : : Type : : Number ,
number . value ( ) / denominator
} ;
} ,
[ & ] ( Angle const & angle ) {
m_value = Angle : : make_degrees ( angle . to_degrees ( ) / denominator ) ;
} ,
2023-09-28 15:18:14 +01:00
[ & ] ( Flex const & flex ) {
m_value = Flex : : make_fr ( flex . to_fr ( ) / denominator ) ;
} ,
2023-03-30 17:34:14 +01:00
[ & ] ( Frequency const & frequency ) {
m_value = Frequency : : make_hertz ( frequency . to_hertz ( ) / denominator ) ;
} ,
[ & ] ( Length const & length ) {
2023-08-26 15:57:31 +01:00
m_value = Length : : make_px ( CSSPixels : : nearest_value_for ( length . to_px ( * context ) / static_cast < double > ( denominator ) ) ) ;
2023-03-30 17:34:14 +01:00
} ,
2023-12-30 17:05:23 +00:00
[ & ] ( Resolution const & resolution ) {
m_value = Resolution : : make_dots_per_pixel ( resolution . to_dots_per_pixel ( ) / denominator ) ;
} ,
2023-03-30 17:34:14 +01:00
[ & ] ( Time const & time ) {
m_value = Time : : make_seconds ( time . to_seconds ( ) / denominator ) ;
} ,
[ & ] ( Percentage const & percentage ) {
m_value = Percentage { percentage . value ( ) / denominator } ;
} ) ;
}
2023-04-11 15:48:06 +01:00
void CalculatedStyleValue : : CalculationResult : : negate ( )
2023-03-30 17:34:14 +01:00
{
2023-04-11 15:48:06 +01:00
m_value . visit (
[ & ] ( Number const & number ) {
2023-05-16 16:57:12 +02:00
m_value = Number { number . type ( ) , 0 - number . value ( ) } ;
2023-04-11 15:48:06 +01:00
} ,
[ & ] ( Angle const & angle ) {
2023-05-16 16:57:12 +02:00
m_value = Angle { 0 - angle . raw_value ( ) , angle . type ( ) } ;
2023-04-11 15:48:06 +01:00
} ,
2023-09-28 15:18:14 +01:00
[ & ] ( Flex const & flex ) {
m_value = Flex { 0 - flex . raw_value ( ) , flex . type ( ) } ;
} ,
2023-04-11 15:48:06 +01:00
[ & ] ( Frequency const & frequency ) {
2023-05-16 16:57:12 +02:00
m_value = Frequency { 0 - frequency . raw_value ( ) , frequency . type ( ) } ;
2023-04-11 15:48:06 +01:00
} ,
[ & ] ( Length const & length ) {
2023-05-16 16:57:12 +02:00
m_value = Length { 0 - length . raw_value ( ) , length . type ( ) } ;
2023-04-11 15:48:06 +01:00
} ,
2023-12-30 17:05:23 +00:00
[ & ] ( Resolution const & resolution ) {
m_value = Resolution { 0 - resolution . raw_value ( ) , resolution . type ( ) } ;
} ,
2023-04-11 15:48:06 +01:00
[ & ] ( Time const & time ) {
2023-05-16 16:57:12 +02:00
m_value = Time { 0 - time . raw_value ( ) , time . type ( ) } ;
2023-04-11 15:48:06 +01:00
} ,
[ & ] ( Percentage const & percentage ) {
2023-05-16 16:57:12 +02:00
m_value = Percentage { 0 - percentage . value ( ) } ;
2023-04-11 15:48:06 +01:00
} ) ;
2023-03-30 17:34:14 +01:00
}
2023-04-11 15:48:06 +01:00
void CalculatedStyleValue : : CalculationResult : : invert ( )
2023-03-30 17:34:14 +01:00
{
2023-04-11 15:48:06 +01:00
// FIXME: Correctly handle division by zero.
m_value . visit (
[ & ] ( Number const & number ) {
m_value = Number { Number : : Type : : Number , 1 / number . value ( ) } ;
} ,
[ & ] ( Angle const & angle ) {
m_value = Angle { 1 / angle . raw_value ( ) , angle . type ( ) } ;
} ,
2023-09-28 15:18:14 +01:00
[ & ] ( Flex const & flex ) {
m_value = Flex { 1 / flex . raw_value ( ) , flex . type ( ) } ;
} ,
2023-04-11 15:48:06 +01:00
[ & ] ( Frequency const & frequency ) {
m_value = Frequency { 1 / frequency . raw_value ( ) , frequency . type ( ) } ;
} ,
[ & ] ( Length const & length ) {
m_value = Length { 1 / length . raw_value ( ) , length . type ( ) } ;
} ,
2023-12-30 17:05:23 +00:00
[ & ] ( Resolution const & resolution ) {
m_value = Resolution { 1 / resolution . raw_value ( ) , resolution . type ( ) } ;
} ,
2023-04-11 15:48:06 +01:00
[ & ] ( Time const & time ) {
m_value = Time { 1 / time . raw_value ( ) , time . type ( ) } ;
} ,
[ & ] ( Percentage const & percentage ) {
m_value = Percentage { 1 / percentage . value ( ) } ;
} ) ;
2023-03-30 17:34:14 +01:00
}
2023-08-22 14:08:15 +01:00
String CalculatedStyleValue : : to_string ( ) const
2023-03-30 17:34:14 +01:00
{
2023-04-11 15:48:06 +01:00
// FIXME: Implement this according to https://www.w3.org/TR/css-values-4/#calc-serialize once that stabilizes.
2023-08-22 14:08:15 +01:00
return MUST ( String : : formatted ( " calc({}) " , m_calculation->to_string())) ;
2023-03-30 17:34:14 +01:00
}
2023-04-11 15:48:06 +01:00
bool CalculatedStyleValue : : equals ( StyleValue const & other ) const
2023-03-30 17:34:14 +01:00
{
2023-04-11 15:48:06 +01:00
if ( type ( ) ! = other . type ( ) )
return false ;
2024-01-09 12:41:43 +01:00
return m_calculation - > equals ( * static_cast < CalculatedStyleValue const & > ( other ) . m_calculation ) ;
2023-03-30 17:34:14 +01:00
}
Optional < Angle > CalculatedStyleValue : : resolve_angle ( ) const
{
2023-06-02 12:39:39 +02:00
auto result = m_calculation - > resolve ( { } , { } ) ;
2023-03-30 17:34:14 +01:00
if ( result . value ( ) . has < Angle > ( ) )
return result . value ( ) . get < Angle > ( ) ;
return { } ;
}
Optional < Angle > CalculatedStyleValue : : resolve_angle_percentage ( Angle const & percentage_basis ) const
{
2023-06-02 12:39:39 +02:00
auto result = m_calculation - > resolve ( { } , percentage_basis ) ;
2023-03-30 17:34:14 +01:00
return result . value ( ) . visit (
[ & ] ( Angle const & angle ) - > Optional < Angle > {
return angle ;
} ,
[ & ] ( Percentage const & percentage ) - > Optional < Angle > {
return percentage_basis . percentage_of ( percentage ) ;
} ,
[ & ] ( auto const & ) - > Optional < Angle > {
return { } ;
} ) ;
}
2023-09-28 15:18:14 +01:00
Optional < Flex > CalculatedStyleValue : : resolve_flex ( ) const
{
auto result = m_calculation - > resolve ( { } , { } ) ;
if ( result . value ( ) . has < Flex > ( ) )
return result . value ( ) . get < Flex > ( ) ;
return { } ;
}
2023-03-30 17:34:14 +01:00
Optional < Frequency > CalculatedStyleValue : : resolve_frequency ( ) const
{
2023-06-02 12:39:39 +02:00
auto result = m_calculation - > resolve ( { } , { } ) ;
2023-03-30 17:34:14 +01:00
if ( result . value ( ) . has < Frequency > ( ) )
return result . value ( ) . get < Frequency > ( ) ;
return { } ;
}
Optional < Frequency > CalculatedStyleValue : : resolve_frequency_percentage ( Frequency const & percentage_basis ) const
{
2023-06-02 12:39:39 +02:00
auto result = m_calculation - > resolve ( { } , percentage_basis ) ;
2023-03-30 17:34:14 +01:00
return result . value ( ) . visit (
[ & ] ( Frequency const & frequency ) - > Optional < Frequency > {
return frequency ;
} ,
[ & ] ( Percentage const & percentage ) - > Optional < Frequency > {
return percentage_basis . percentage_of ( percentage ) ;
} ,
[ & ] ( auto const & ) - > Optional < Frequency > {
return { } ;
} ) ;
}
2023-06-02 12:39:39 +02:00
Optional < Length > CalculatedStyleValue : : resolve_length ( Length : : ResolutionContext const & context ) const
2023-03-30 17:34:14 +01:00
{
2023-06-02 12:39:39 +02:00
auto result = m_calculation - > resolve ( context , { } ) ;
2023-03-30 17:34:14 +01:00
if ( result . value ( ) . has < Length > ( ) )
return result . value ( ) . get < Length > ( ) ;
return { } ;
}
2023-06-02 12:39:39 +02:00
Optional < Length > CalculatedStyleValue : : resolve_length ( Layout : : Node const & layout_node ) const
{
return resolve_length ( Length : : ResolutionContext : : for_layout_node ( layout_node ) ) ;
}
2023-03-30 17:34:14 +01:00
Optional < Length > CalculatedStyleValue : : resolve_length_percentage ( Layout : : Node const & layout_node , Length const & percentage_basis ) const
{
2023-10-04 16:24:24 +02:00
return resolve_length_percentage ( Length : : ResolutionContext : : for_layout_node ( layout_node ) , percentage_basis ) ;
2023-03-30 17:34:14 +01:00
}
2023-08-29 18:57:09 +02:00
Optional < Length > CalculatedStyleValue : : resolve_length_percentage ( Layout : : Node const & layout_node , CSSPixels percentage_basis ) const
{
2023-10-04 16:24:24 +02:00
return resolve_length_percentage ( Length : : ResolutionContext : : for_layout_node ( layout_node ) , Length : : make_px ( percentage_basis ) ) ;
}
Optional < Length > CalculatedStyleValue : : resolve_length_percentage ( Length : : ResolutionContext const & resolution_context , Length const & percentage_basis ) const
{
auto result = m_calculation - > resolve ( resolution_context , percentage_basis ) ;
2023-08-29 18:57:09 +02:00
return result . value ( ) . visit (
[ & ] ( Length const & length ) - > Optional < Length > {
return length ;
} ,
[ & ] ( Percentage const & percentage ) - > Optional < Length > {
2023-10-04 16:24:24 +02:00
return percentage_basis . percentage_of ( percentage ) ;
2023-08-29 18:57:09 +02:00
} ,
[ & ] ( auto const & ) - > Optional < Length > {
return { } ;
} ) ;
}
2023-03-30 17:34:14 +01:00
Optional < Percentage > CalculatedStyleValue : : resolve_percentage ( ) const
{
2023-06-02 12:39:39 +02:00
auto result = m_calculation - > resolve ( { } , { } ) ;
2023-03-30 17:34:14 +01:00
if ( result . value ( ) . has < Percentage > ( ) )
return result . value ( ) . get < Percentage > ( ) ;
return { } ;
}
2023-12-30 17:05:23 +00:00
Optional < Resolution > CalculatedStyleValue : : resolve_resolution ( ) const
{
auto result = m_calculation - > resolve ( { } , { } ) ;
if ( result . value ( ) . has < Resolution > ( ) )
return result . value ( ) . get < Resolution > ( ) ;
return { } ;
}
2023-03-30 17:34:14 +01:00
Optional < Time > CalculatedStyleValue : : resolve_time ( ) const
{
2023-06-02 12:39:39 +02:00
auto result = m_calculation - > resolve ( { } , { } ) ;
2023-03-30 17:34:14 +01:00
if ( result . value ( ) . has < Time > ( ) )
return result . value ( ) . get < Time > ( ) ;
return { } ;
}
Optional < Time > CalculatedStyleValue : : resolve_time_percentage ( Time const & percentage_basis ) const
{
2023-06-02 12:39:39 +02:00
auto result = m_calculation - > resolve ( { } , percentage_basis ) ;
2023-03-30 17:34:14 +01:00
return result . value ( ) . visit (
[ & ] ( Time const & time ) - > Optional < Time > {
return time ;
} ,
[ & ] ( auto const & ) - > Optional < Time > {
return { } ;
} ) ;
}
2023-05-27 21:10:21 +02:00
Optional < double > CalculatedStyleValue : : resolve_number ( ) const
2023-03-30 17:34:14 +01:00
{
2023-06-02 12:39:39 +02:00
auto result = m_calculation - > resolve ( { } , { } ) ;
2023-03-30 17:34:14 +01:00
if ( result . value ( ) . has < Number > ( ) )
return result . value ( ) . get < Number > ( ) . value ( ) ;
return { } ;
}
2023-09-07 15:11:09 +01:00
Optional < i64 > CalculatedStyleValue : : resolve_integer ( ) const
2023-03-30 17:34:14 +01:00
{
2023-06-02 12:39:39 +02:00
auto result = m_calculation - > resolve ( { } , { } ) ;
2023-03-30 17:34:14 +01:00
if ( result . value ( ) . has < Number > ( ) )
return result . value ( ) . get < Number > ( ) . integer_value ( ) ;
return { } ;
}
bool CalculatedStyleValue : : contains_percentage ( ) const
{
2023-04-11 15:48:06 +01:00
return m_calculation - > contains_percentage ( ) ;
2023-03-30 17:34:14 +01:00
}
}