2020-01-18 09:38:21 +01:00
/*
* Copyright ( c ) 2018 - 2020 , Andreas Kling < kling @ serenityos . org >
2022-02-02 20:39:04 +00:00
* Copyright ( c ) 2021 - 2022 , Sam Atkins < atkinssj @ serenityos . org >
2022-01-24 17:38:29 +00:00
* Copyright ( c ) 2021 , Tobias Christiansen < tobyase @ serenityos . org >
2020-01-18 09:38:21 +01:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 09:38:21 +01:00
*/
2020-02-14 21:41:10 +01:00
# include <AK/ByteBuffer.h>
2020-05-25 14:54:27 -04:00
# include <LibGfx/Palette.h>
2022-02-02 20:39:04 +00:00
# include <LibWeb/CSS/Serialize.h>
2020-03-07 10:32:51 +01:00
# include <LibWeb/CSS/StyleValue.h>
# include <LibWeb/DOM/Document.h>
2021-11-18 15:01:28 +01:00
# include <LibWeb/HTML/BrowsingContext.h>
2020-06-02 13:51:30 +02:00
# include <LibWeb/Loader/LoadRequest.h>
2020-06-01 20:42:50 +02:00
# include <LibWeb/Loader/ResourceLoader.h>
2021-08-24 16:28:08 +02:00
# include <LibWeb/Page/Page.h>
2022-07-31 01:11:59 +01:00
# include <LibWeb/Painting/GradientPainting.h>
2022-10-30 15:43:42 +00:00
# include <LibWeb/Platform/Timer.h>
2019-06-22 21:48:21 +02:00
2020-07-26 20:01:35 +02:00
namespace Web : : CSS {
2020-03-07 10:27:02 +01:00
2019-06-22 21:48:21 +02:00
StyleValue : : StyleValue ( Type type )
: m_type ( type )
{
}
2022-07-31 01:11:59 +01:00
AbstractImageStyleValue const & StyleValue : : as_abstract_image ( ) const
{
VERIFY ( is_abstract_image ( ) ) ;
return static_cast < AbstractImageStyleValue const & > ( * this ) ;
}
2022-02-21 17:43:30 +00:00
AngleStyleValue const & StyleValue : : as_angle ( ) const
{
VERIFY ( is_angle ( ) ) ;
return static_cast < AngleStyleValue const & > ( * this ) ;
}
2021-09-23 19:54:19 +01:00
BackgroundStyleValue const & StyleValue : : as_background ( ) const
2021-09-22 12:42:54 +01:00
{
2021-09-23 19:54:19 +01:00
VERIFY ( is_background ( ) ) ;
return static_cast < BackgroundStyleValue const & > ( * this ) ;
}
BackgroundRepeatStyleValue const & StyleValue : : as_background_repeat ( ) const
{
VERIFY ( is_background_repeat ( ) ) ;
return static_cast < BackgroundRepeatStyleValue const & > ( * this ) ;
}
2021-11-05 12:18:23 +00:00
BackgroundSizeStyleValue const & StyleValue : : as_background_size ( ) const
{
VERIFY ( is_background_size ( ) ) ;
return static_cast < BackgroundSizeStyleValue const & > ( * this ) ;
}
2021-09-23 19:54:19 +01:00
BorderStyleValue const & StyleValue : : as_border ( ) const
{
VERIFY ( is_border ( ) ) ;
return static_cast < BorderStyleValue const & > ( * this ) ;
}
BorderRadiusStyleValue const & StyleValue : : as_border_radius ( ) const
{
VERIFY ( is_border_radius ( ) ) ;
return static_cast < BorderRadiusStyleValue const & > ( * this ) ;
}
2022-04-18 17:04:38 +01:00
BorderRadiusShorthandStyleValue const & StyleValue : : as_border_radius_shorthand ( ) const
{
VERIFY ( is_border_radius_shorthand ( ) ) ;
return static_cast < BorderRadiusShorthandStyleValue const & > ( * this ) ;
}
2022-03-23 16:55:22 +00:00
ShadowStyleValue const & StyleValue : : as_shadow ( ) const
2021-09-23 19:54:19 +01:00
{
2022-03-23 16:55:22 +00:00
VERIFY ( is_shadow ( ) ) ;
return static_cast < ShadowStyleValue const & > ( * this ) ;
2021-09-23 19:54:19 +01:00
}
CalculatedStyleValue const & StyleValue : : as_calculated ( ) const
{
VERIFY ( is_calculated ( ) ) ;
return static_cast < CalculatedStyleValue const & > ( * this ) ;
}
ColorStyleValue const & StyleValue : : as_color ( ) const
{
VERIFY ( is_color ( ) ) ;
return static_cast < ColorStyleValue const & > ( * this ) ;
}
2022-10-28 20:44:00 +01:00
ConicGradientStyleValue const & StyleValue : : as_conic_gradient ( ) const
{
VERIFY ( is_conic_gradient ( ) ) ;
return static_cast < ConicGradientStyleValue const & > ( * this ) ;
}
2022-02-23 19:56:25 +00:00
ContentStyleValue const & StyleValue : : as_content ( ) const
{
VERIFY ( is_content ( ) ) ;
return static_cast < ContentStyleValue const & > ( * this ) ;
}
2022-09-15 08:31:14 +01:00
FilterValueListStyleValue const & StyleValue : : as_filter_value_list ( ) const
{
VERIFY ( is_filter_value_list ( ) ) ;
return static_cast < FilterValueListStyleValue const & > ( * this ) ;
}
2021-09-23 19:54:19 +01:00
FlexStyleValue const & StyleValue : : as_flex ( ) const
{
VERIFY ( is_flex ( ) ) ;
return static_cast < FlexStyleValue const & > ( * this ) ;
}
FlexFlowStyleValue const & StyleValue : : as_flex_flow ( ) const
{
VERIFY ( is_flex_flow ( ) ) ;
return static_cast < FlexFlowStyleValue const & > ( * this ) ;
}
FontStyleValue const & StyleValue : : as_font ( ) const
{
VERIFY ( is_font ( ) ) ;
return static_cast < FontStyleValue const & > ( * this ) ;
}
2021-09-22 12:42:54 +01:00
2022-02-21 17:49:47 +00:00
FrequencyStyleValue const & StyleValue : : as_frequency ( ) const
{
VERIFY ( is_frequency ( ) ) ;
return static_cast < FrequencyStyleValue const & > ( * this ) ;
}
2022-08-24 12:25:56 +02:00
GridTrackPlacementShorthandStyleValue const & StyleValue : : as_grid_track_placement_shorthand ( ) const
{
VERIFY ( is_grid_track_placement_shorthand ( ) ) ;
return static_cast < GridTrackPlacementShorthandStyleValue const & > ( * this ) ;
}
2022-08-24 12:31:00 +02:00
GridTrackPlacementStyleValue const & StyleValue : : as_grid_track_placement ( ) const
{
VERIFY ( is_grid_track_placement ( ) ) ;
return static_cast < GridTrackPlacementStyleValue const & > ( * this ) ;
}
2021-09-23 19:54:19 +01:00
IdentifierStyleValue const & StyleValue : : as_identifier ( ) const
{
VERIFY ( is_identifier ( ) ) ;
return static_cast < IdentifierStyleValue const & > ( * this ) ;
}
ImageStyleValue const & StyleValue : : as_image ( ) const
{
VERIFY ( is_image ( ) ) ;
return static_cast < ImageStyleValue const & > ( * this ) ;
}
InheritStyleValue const & StyleValue : : as_inherit ( ) const
{
VERIFY ( is_inherit ( ) ) ;
return static_cast < InheritStyleValue const & > ( * this ) ;
}
InitialStyleValue const & StyleValue : : as_initial ( ) const
{
VERIFY ( is_initial ( ) ) ;
return static_cast < InitialStyleValue const & > ( * this ) ;
}
LengthStyleValue const & StyleValue : : as_length ( ) const
{
VERIFY ( is_length ( ) ) ;
return static_cast < LengthStyleValue const & > ( * this ) ;
}
2022-10-30 13:27:57 +01:00
GridTrackSizeStyleValue const & StyleValue : : as_grid_track_size_list ( ) const
2022-08-24 12:27:56 +02:00
{
2022-10-30 13:27:57 +01:00
VERIFY ( is_grid_track_size_list ( ) ) ;
2022-08-24 12:27:56 +02:00
return static_cast < GridTrackSizeStyleValue const & > ( * this ) ;
}
2022-07-12 00:09:29 +01:00
LinearGradientStyleValue const & StyleValue : : as_linear_gradient ( ) const
{
VERIFY ( is_linear_gradient ( ) ) ;
return static_cast < LinearGradientStyleValue const & > ( * this ) ;
}
2021-09-23 19:54:19 +01:00
ListStyleStyleValue const & StyleValue : : as_list_style ( ) const
{
VERIFY ( is_list_style ( ) ) ;
return static_cast < ListStyleStyleValue const & > ( * this ) ;
}
NumericStyleValue const & StyleValue : : as_numeric ( ) const
{
VERIFY ( is_numeric ( ) ) ;
return static_cast < NumericStyleValue const & > ( * this ) ;
}
OverflowStyleValue const & StyleValue : : as_overflow ( ) const
{
VERIFY ( is_overflow ( ) ) ;
return static_cast < OverflowStyleValue const & > ( * this ) ;
}
2022-01-14 17:09:02 +00:00
PercentageStyleValue const & StyleValue : : as_percentage ( ) const
{
VERIFY ( is_percentage ( ) ) ;
return static_cast < PercentageStyleValue const & > ( * this ) ;
}
2021-10-31 16:02:29 +00:00
PositionStyleValue const & StyleValue : : as_position ( ) const
{
VERIFY ( is_position ( ) ) ;
return static_cast < PositionStyleValue const & > ( * this ) ;
}
2022-11-11 18:13:00 +01:00
RadialGradientStyleValue const & StyleValue : : as_radial_gradient ( ) const
{
VERIFY ( is_radial_gradient ( ) ) ;
return static_cast < RadialGradientStyleValue const & > ( * this ) ;
}
2022-07-31 18:46:35 +02:00
RectStyleValue const & StyleValue : : as_rect ( ) const
{
VERIFY ( is_rect ( ) ) ;
return static_cast < RectStyleValue const & > ( * this ) ;
}
2022-02-21 17:51:01 +00:00
ResolutionStyleValue const & StyleValue : : as_resolution ( ) const
{
VERIFY ( is_resolution ( ) ) ;
return static_cast < ResolutionStyleValue const & > ( * this ) ;
}
2021-09-23 19:54:19 +01:00
StringStyleValue const & StyleValue : : as_string ( ) const
{
VERIFY ( is_string ( ) ) ;
return static_cast < StringStyleValue const & > ( * this ) ;
}
TextDecorationStyleValue const & StyleValue : : as_text_decoration ( ) const
{
VERIFY ( is_text_decoration ( ) ) ;
return static_cast < TextDecorationStyleValue const & > ( * this ) ;
}
2022-02-21 19:29:43 +00:00
TimeStyleValue const & StyleValue : : as_time ( ) const
{
VERIFY ( is_time ( ) ) ;
return static_cast < TimeStyleValue const & > ( * this ) ;
}
2021-09-23 19:54:19 +01:00
TransformationStyleValue const & StyleValue : : as_transformation ( ) const
{
VERIFY ( is_transformation ( ) ) ;
return static_cast < TransformationStyleValue const & > ( * this ) ;
}
2021-12-03 12:28:14 +00:00
UnresolvedStyleValue const & StyleValue : : as_unresolved ( ) const
{
VERIFY ( is_unresolved ( ) ) ;
return static_cast < UnresolvedStyleValue const & > ( * this ) ;
}
2021-09-23 19:54:19 +01:00
UnsetStyleValue const & StyleValue : : as_unset ( ) const
{
VERIFY ( is_unset ( ) ) ;
return static_cast < UnsetStyleValue const & > ( * this ) ;
}
StyleValueList const & StyleValue : : as_value_list ( ) const
{
VERIFY ( is_value_list ( ) ) ;
return static_cast < StyleValueList const & > ( * this ) ;
}
2021-11-11 11:47:31 +00:00
BackgroundStyleValue : : BackgroundStyleValue (
NonnullRefPtr < StyleValue > color ,
NonnullRefPtr < StyleValue > image ,
NonnullRefPtr < StyleValue > position ,
NonnullRefPtr < StyleValue > size ,
NonnullRefPtr < StyleValue > repeat ,
NonnullRefPtr < StyleValue > attachment ,
NonnullRefPtr < StyleValue > origin ,
NonnullRefPtr < StyleValue > clip )
: StyleValue ( Type : : Background )
, m_color ( color )
, m_image ( image )
, m_position ( position )
, m_size ( size )
, m_repeat ( repeat )
, m_attachment ( attachment )
, m_origin ( origin )
, m_clip ( clip )
{
auto layer_count = [ ] ( auto style_value ) - > size_t {
if ( style_value - > is_value_list ( ) )
return style_value - > as_value_list ( ) . size ( ) ;
else
return 1 ;
} ;
m_layer_count = max ( layer_count ( m_image ) , layer_count ( m_position ) ) ;
m_layer_count = max ( m_layer_count , layer_count ( m_size ) ) ;
m_layer_count = max ( m_layer_count , layer_count ( m_repeat ) ) ;
m_layer_count = max ( m_layer_count , layer_count ( m_attachment ) ) ;
m_layer_count = max ( m_layer_count , layer_count ( m_origin ) ) ;
m_layer_count = max ( m_layer_count , layer_count ( m_clip ) ) ;
VERIFY ( ! m_color - > is_value_list ( ) ) ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString BackgroundStyleValue : : to_deprecated_string ( ) const
2021-11-11 11:47:31 +00:00
{
if ( m_layer_count = = 1 ) {
2022-12-06 01:12:49 +00:00
return DeprecatedString : : formatted ( " {} {} {} {} {} {} {} {} " , m_color - > to_deprecated_string ( ) , m_image - > to_deprecated_string ( ) , m_position - > to_deprecated_string ( ) , m_size - > to_deprecated_string ( ) , m_repeat - > to_deprecated_string ( ) , m_attachment - > to_deprecated_string ( ) , m_origin - > to_deprecated_string ( ) , m_clip - > to_deprecated_string ( ) ) ;
2021-11-11 11:47:31 +00:00
}
auto get_layer_value_string = [ ] ( NonnullRefPtr < StyleValue > const & style_value , size_t index ) {
if ( style_value - > is_value_list ( ) )
2022-12-06 01:12:49 +00:00
return style_value - > as_value_list ( ) . value_at ( index , true ) - > to_deprecated_string ( ) ;
return style_value - > to_deprecated_string ( ) ;
2021-11-11 11:47:31 +00:00
} ;
StringBuilder builder ;
for ( size_t i = 0 ; i < m_layer_count ; i + + ) {
if ( i )
2022-07-11 17:32:29 +00:00
builder . append ( " , " sv ) ;
2021-11-11 11:47:31 +00:00
if ( i = = m_layer_count - 1 )
2022-12-06 01:12:49 +00:00
builder . appendff ( " {} " , m_color - > to_deprecated_string ( ) ) ;
2021-11-11 11:47:31 +00:00
builder . appendff ( " {} {} {} {} {} {} {} " , get_layer_value_string ( m_image , i ) , get_layer_value_string ( m_position , i ) , get_layer_value_string ( m_size , i ) , get_layer_value_string ( m_repeat , i ) , get_layer_value_string ( m_attachment , i ) , get_layer_value_string ( m_origin , i ) , get_layer_value_string ( m_clip , i ) ) ;
}
2022-12-06 01:12:49 +00:00
return builder . to_deprecated_string ( ) ;
2021-11-11 11:47:31 +00:00
}
2022-04-18 17:42:03 +01:00
bool BackgroundStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_background ( ) ;
return m_color - > equals ( typed_other . m_color )
& & m_image - > equals ( typed_other . m_image )
& & m_position - > equals ( typed_other . m_position )
& & m_size - > equals ( typed_other . m_size )
& & m_repeat - > equals ( typed_other . m_repeat )
& & m_attachment - > equals ( typed_other . m_attachment )
& & m_origin - > equals ( typed_other . m_origin )
& & m_clip - > equals ( typed_other . m_clip ) ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString BackgroundRepeatStyleValue : : to_deprecated_string ( ) const
2022-02-02 20:39:04 +00:00
{
2022-12-04 18:02:33 +00:00
return DeprecatedString : : formatted ( " {} {} " , CSS : : to_string ( m_repeat_x ) , CSS : : to_string ( m_repeat_y ) ) ;
2022-02-02 20:39:04 +00:00
}
2022-04-18 17:42:03 +01:00
bool BackgroundRepeatStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_background_repeat ( ) ;
return m_repeat_x = = typed_other . m_repeat_x & & m_repeat_y = = typed_other . m_repeat_y ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString BackgroundSizeStyleValue : : to_deprecated_string ( ) const
2022-02-02 20:39:04 +00:00
{
2022-12-06 01:12:49 +00:00
return DeprecatedString : : formatted ( " {} {} " , m_size_x . to_deprecated_string ( ) , m_size_y . to_deprecated_string ( ) ) ;
2022-02-02 20:39:04 +00:00
}
2022-04-18 17:42:03 +01:00
bool BackgroundSizeStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_background_size ( ) ;
return m_size_x = = typed_other . m_size_x & & m_size_y = = typed_other . m_size_y ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString BorderStyleValue : : to_deprecated_string ( ) const
2022-02-02 20:39:04 +00:00
{
2022-12-06 01:12:49 +00:00
return DeprecatedString : : formatted ( " {} {} {} " , m_border_width - > to_deprecated_string ( ) , m_border_style - > to_deprecated_string ( ) , m_border_color - > to_deprecated_string ( ) ) ;
2022-02-02 20:39:04 +00:00
}
2022-04-18 17:42:03 +01:00
bool BorderStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_border ( ) ;
return m_border_width - > equals ( typed_other . m_border_width )
& & m_border_style - > equals ( typed_other . m_border_style )
& & m_border_color - > equals ( typed_other . m_border_color ) ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString BorderRadiusStyleValue : : to_deprecated_string ( ) const
2022-02-02 20:39:04 +00:00
{
2022-04-03 17:03:32 -03:00
if ( m_horizontal_radius = = m_vertical_radius )
2022-12-06 01:12:49 +00:00
return m_horizontal_radius . to_deprecated_string ( ) ;
return DeprecatedString : : formatted ( " {} / {} " , m_horizontal_radius . to_deprecated_string ( ) , m_vertical_radius . to_deprecated_string ( ) ) ;
2022-02-02 20:39:04 +00:00
}
2022-04-18 17:42:03 +01:00
bool BorderRadiusStyleValue : : equals ( StyleValue const & other ) const
2022-02-02 20:39:04 +00:00
{
2022-04-18 17:42:03 +01:00
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_border_radius ( ) ;
return m_is_elliptical = = typed_other . m_is_elliptical
& & m_horizontal_radius = = typed_other . m_horizontal_radius
& & m_vertical_radius = = typed_other . m_vertical_radius ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString BorderRadiusShorthandStyleValue : : to_deprecated_string ( ) const
2022-04-18 17:42:03 +01:00
{
2022-12-06 01:12:49 +00:00
return DeprecatedString : : formatted ( " {} {} {} {} / {} {} {} {} " , m_top_left - > horizontal_radius ( ) . to_deprecated_string ( ) , m_top_right - > horizontal_radius ( ) . to_deprecated_string ( ) , m_bottom_right - > horizontal_radius ( ) . to_deprecated_string ( ) , m_bottom_left - > horizontal_radius ( ) . to_deprecated_string ( ) , m_top_left - > vertical_radius ( ) . to_deprecated_string ( ) , m_top_right - > vertical_radius ( ) . to_deprecated_string ( ) , m_bottom_right - > vertical_radius ( ) . to_deprecated_string ( ) , m_bottom_left - > vertical_radius ( ) . to_deprecated_string ( ) ) ;
2022-04-18 17:42:03 +01:00
}
bool BorderRadiusShorthandStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_border_radius_shorthand ( ) ;
return m_top_left - > equals ( typed_other . m_top_left )
& & m_top_right - > equals ( typed_other . m_top_right )
& & m_bottom_right - > equals ( typed_other . m_bottom_right )
& & m_bottom_left - > equals ( typed_other . m_bottom_left ) ;
2022-01-27 14:51:51 +00:00
}
2022-02-18 12:07:09 +00:00
void CalculatedStyleValue : : CalculationResult : : add ( CalculationResult const & other , Layout : : Node const * layout_node , PercentageBasis const & percentage_basis )
2022-01-27 14:50:31 +00:00
{
add_or_subtract_internal ( SumOperation : : Add , other , layout_node , percentage_basis ) ;
}
2022-02-18 12:07:09 +00:00
void CalculatedStyleValue : : CalculationResult : : subtract ( CalculationResult const & other , Layout : : Node const * layout_node , PercentageBasis const & percentage_basis )
2022-01-27 14:50:31 +00:00
{
add_or_subtract_internal ( SumOperation : : Subtract , other , layout_node , percentage_basis ) ;
}
2022-02-18 12:07:09 +00:00
void CalculatedStyleValue : : CalculationResult : : add_or_subtract_internal ( SumOperation op , CalculationResult const & other , Layout : : Node const * layout_node , PercentageBasis const & percentage_basis )
2022-01-27 14:50:31 +00: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 (
2022-02-02 12:34:32 +00:00
[ & ] ( Number const & number ) {
auto other_number = other . m_value . get < Number > ( ) ;
if ( op = = SumOperation : : Add ) {
2022-03-21 21:03:17 +00:00
m_value = number + other_number ;
2022-02-02 12:34:32 +00:00
} else {
2022-03-21 21:03:17 +00:00
m_value = number - other_number ;
2022-02-02 12:34:32 +00:00
}
2022-01-27 14:50:31 +00:00
} ,
2022-02-21 17:43:30 +00:00
[ & ] ( 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 ) ;
}
} ,
2022-02-21 17:49:47 +00: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 ) ;
}
} ,
2022-01-27 14:50:31 +00:00
[ & ] ( Length const & length ) {
auto this_px = length . to_px ( * layout_node ) ;
if ( other . m_value . has < Length > ( ) ) {
auto other_px = other . m_value . get < Length > ( ) . to_px ( * layout_node ) ;
if ( op = = SumOperation : : Add )
m_value = Length : : make_px ( this_px + other_px ) ;
else
m_value = Length : : make_px ( this_px - other_px ) ;
} else {
2022-02-18 12:07:09 +00:00
VERIFY ( percentage_basis . has < Length > ( ) ) ;
2022-01-27 14:50:31 +00:00
2022-02-18 12:07:09 +00:00
auto other_px = percentage_basis . get < Length > ( ) . percentage_of ( other . m_value . get < Percentage > ( ) ) . to_px ( * layout_node ) ;
2022-01-27 14:50:31 +00:00
if ( op = = SumOperation : : Add )
m_value = Length : : make_px ( this_px + other_px ) ;
else
m_value = Length : : make_px ( this_px - other_px ) ;
}
} ,
2022-02-21 19:29:43 +00: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 ) ;
}
} ,
2022-01-27 14:50:31 +00:00
[ & ] ( 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 ;
2022-06-29 23:32:05 +01:00
if ( op = = SumOperation : : Add ) {
new_value . add ( * this , layout_node , percentage_basis ) ;
} else {
// Turn 'this - other' into '-other + this', as 'A + B == B + A', but 'A - B != B - A'
new_value . multiply_by ( { Number { Number : : Type : : Integer , - 1.0f } } , layout_node ) ;
2022-01-27 14:50:31 +00:00
new_value . add ( * this , layout_node , percentage_basis ) ;
2022-06-29 23:32:05 +01:00
}
2022-01-27 14:50:31 +00:00
* this = new_value ;
} ) ;
}
void CalculatedStyleValue : : CalculationResult : : multiply_by ( CalculationResult const & other , Layout : : Node const * layout_node )
{
// We know from validation when resolving the type, that at least one side must be a <number> or <integer>.
// Both of these are represented as a float.
2022-02-02 12:34:32 +00:00
VERIFY ( m_value . has < Number > ( ) | | other . m_value . has < Number > ( ) ) ;
bool other_is_number = other . m_value . has < Number > ( ) ;
2022-01-27 14:50:31 +00:00
m_value . visit (
2022-02-02 12:34:32 +00:00
[ & ] ( Number const & number ) {
2022-01-27 14:50:31 +00:00
if ( other_is_number ) {
2022-03-21 21:03:17 +00:00
m_value = number * other . m_value . get < Number > ( ) ;
2022-01-27 14:50:31 +00:00
} else {
// Avoid duplicating all the logic by swapping `this` and `other`.
CalculationResult new_value = other ;
new_value . multiply_by ( * this , layout_node ) ;
* this = new_value ;
}
} ,
2022-02-21 17:43:30 +00:00
[ & ] ( Angle const & angle ) {
2022-03-21 21:03:17 +00:00
m_value = Angle : : make_degrees ( angle . to_degrees ( ) * other . m_value . get < Number > ( ) . value ( ) ) ;
2022-02-21 17:43:30 +00:00
} ,
2022-02-21 17:49:47 +00:00
[ & ] ( Frequency const & frequency ) {
2022-03-21 21:03:17 +00:00
m_value = Frequency : : make_hertz ( frequency . to_hertz ( ) * other . m_value . get < Number > ( ) . value ( ) ) ;
2022-02-21 17:49:47 +00:00
} ,
2022-01-27 14:50:31 +00:00
[ & ] ( Length const & length ) {
2022-01-27 14:51:51 +00:00
VERIFY ( layout_node ) ;
2022-03-21 21:03:17 +00:00
m_value = Length : : make_px ( length . to_px ( * layout_node ) * other . m_value . get < Number > ( ) . value ( ) ) ;
2022-01-27 14:50:31 +00:00
} ,
2022-02-21 19:29:43 +00:00
[ & ] ( Time const & time ) {
2022-03-21 21:03:17 +00:00
m_value = Time : : make_seconds ( time . to_seconds ( ) * other . m_value . get < Number > ( ) . value ( ) ) ;
2022-02-21 19:29:43 +00:00
} ,
2022-01-27 14:50:31 +00:00
[ & ] ( Percentage const & percentage ) {
2022-03-21 21:03:17 +00:00
m_value = Percentage { percentage . value ( ) * other . m_value . get < Number > ( ) . value ( ) } ;
2022-01-27 14:50:31 +00:00
} ) ;
}
void CalculatedStyleValue : : CalculationResult : : divide_by ( CalculationResult const & other , Layout : : Node const * layout_node )
{
// We know from validation when resolving the type, that `other` must be a <number> or <integer>.
2022-02-02 12:34:32 +00:00
// Both of these are represented as a Number.
2022-03-21 21:03:17 +00:00
auto denominator = other . m_value . get < Number > ( ) . value ( ) ;
2022-01-27 14:50:31 +00:00
// FIXME: Dividing by 0 is invalid, and should be caught during parsing.
VERIFY ( denominator ! = 0.0f ) ;
m_value . visit (
2022-02-02 12:34:32 +00:00
[ & ] ( Number const & number ) {
m_value = Number {
2022-03-21 21:03:17 +00:00
Number : : Type : : Number ,
number . value ( ) / denominator
2022-02-02 12:34:32 +00:00
} ;
2022-01-27 14:50:31 +00:00
} ,
2022-02-21 17:43:30 +00:00
[ & ] ( Angle const & angle ) {
m_value = Angle : : make_degrees ( angle . to_degrees ( ) / denominator ) ;
} ,
2022-02-21 17:49:47 +00:00
[ & ] ( Frequency const & frequency ) {
m_value = Frequency : : make_hertz ( frequency . to_hertz ( ) / denominator ) ;
} ,
2022-01-27 14:50:31 +00:00
[ & ] ( Length const & length ) {
2022-01-27 14:51:51 +00:00
VERIFY ( layout_node ) ;
2022-01-27 14:50:31 +00:00
m_value = Length : : make_px ( length . to_px ( * layout_node ) / denominator ) ;
} ,
2022-02-21 19:29:43 +00:00
[ & ] ( Time const & time ) {
m_value = Time : : make_seconds ( time . to_seconds ( ) / denominator ) ;
} ,
2022-01-27 14:50:31 +00:00
[ & ] ( Percentage const & percentage ) {
m_value = Percentage { percentage . value ( ) / denominator } ;
} ) ;
2022-02-02 20:39:04 +00:00
}
2022-12-06 01:12:49 +00:00
DeprecatedString CalculatedStyleValue : : to_deprecated_string ( ) const
2022-02-02 15:34:13 +00:00
{
2022-12-06 01:12:49 +00:00
return DeprecatedString : : formatted ( " calc({}) " , m_expression - > to_deprecated_string ( ) ) ;
2022-02-02 15:34:13 +00:00
}
2022-04-18 17:42:03 +01:00
bool CalculatedStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
// This is a case where comparing the strings actually makes sense.
2022-12-06 01:12:49 +00:00
return to_deprecated_string ( ) = = other . to_deprecated_string ( ) ;
2022-04-18 17:42:03 +01:00
}
2022-12-06 01:12:49 +00:00
DeprecatedString CalculatedStyleValue : : CalcNumberValue : : to_deprecated_string ( ) const
2022-02-02 15:34:13 +00:00
{
return value . visit (
2022-12-04 18:02:33 +00:00
[ ] ( Number const & number ) { return DeprecatedString : : number ( number . value ( ) ) ; } ,
2022-12-06 01:12:49 +00:00
[ ] ( NonnullOwnPtr < CalcNumberSum > const & sum ) { return DeprecatedString : : formatted ( " ({}) " , sum - > to_deprecated_string ( ) ) ; } ) ;
2022-02-02 15:34:13 +00:00
}
2022-12-06 01:12:49 +00:00
DeprecatedString CalculatedStyleValue : : CalcValue : : to_deprecated_string ( ) const
2022-02-02 15:34:13 +00:00
{
return value . visit (
2022-12-04 18:02:33 +00:00
[ ] ( Number const & number ) { return DeprecatedString : : number ( number . value ( ) ) ; } ,
2022-12-06 01:12:49 +00:00
[ ] ( NonnullOwnPtr < CalcSum > const & sum ) { return DeprecatedString : : formatted ( " ({}) " , sum - > to_deprecated_string ( ) ) ; } ,
[ ] ( auto const & v ) { return v . to_deprecated_string ( ) ; } ) ;
2022-02-02 15:34:13 +00:00
}
2022-12-06 01:12:49 +00:00
DeprecatedString CalculatedStyleValue : : CalcSum : : to_deprecated_string ( ) const
2022-02-02 15:34:13 +00:00
{
StringBuilder builder ;
2022-12-06 01:12:49 +00:00
builder . append ( first_calc_product - > to_deprecated_string ( ) ) ;
2022-02-02 15:34:13 +00:00
for ( auto const & item : zero_or_more_additional_calc_products )
2022-12-06 01:12:49 +00:00
builder . append ( item . to_deprecated_string ( ) ) ;
return builder . to_deprecated_string ( ) ;
2022-02-02 15:34:13 +00:00
}
2022-12-06 01:12:49 +00:00
DeprecatedString CalculatedStyleValue : : CalcNumberSum : : to_deprecated_string ( ) const
2022-02-02 15:34:13 +00:00
{
StringBuilder builder ;
2022-12-06 01:12:49 +00:00
builder . append ( first_calc_number_product - > to_deprecated_string ( ) ) ;
2022-02-02 15:34:13 +00:00
for ( auto const & item : zero_or_more_additional_calc_number_products )
2022-12-06 01:12:49 +00:00
builder . append ( item . to_deprecated_string ( ) ) ;
return builder . to_deprecated_string ( ) ;
2022-02-02 15:34:13 +00:00
}
2022-12-06 01:12:49 +00:00
DeprecatedString CalculatedStyleValue : : CalcProduct : : to_deprecated_string ( ) const
2022-02-02 15:34:13 +00:00
{
StringBuilder builder ;
2022-12-06 01:12:49 +00:00
builder . append ( first_calc_value . to_deprecated_string ( ) ) ;
2022-02-02 15:34:13 +00:00
for ( auto const & item : zero_or_more_additional_calc_values )
2022-12-06 01:12:49 +00:00
builder . append ( item . to_deprecated_string ( ) ) ;
return builder . to_deprecated_string ( ) ;
2022-02-02 15:34:13 +00:00
}
2022-12-06 01:12:49 +00:00
DeprecatedString CalculatedStyleValue : : CalcSumPartWithOperator : : to_deprecated_string ( ) const
2022-02-02 15:34:13 +00:00
{
2022-12-06 01:12:49 +00:00
return DeprecatedString : : formatted ( " {} {} " , op = = SumOperation : : Add ? " + " sv : " - " sv , value - > to_deprecated_string ( ) ) ;
2022-02-02 15:34:13 +00:00
}
2022-12-06 01:12:49 +00:00
DeprecatedString CalculatedStyleValue : : CalcProductPartWithOperator : : to_deprecated_string ( ) const
2022-02-02 15:34:13 +00:00
{
auto value_string = value . visit (
2022-12-06 01:12:49 +00:00
[ ] ( CalcValue const & v ) { return v . to_deprecated_string ( ) ; } ,
[ ] ( CalcNumberValue const & v ) { return v . to_deprecated_string ( ) ; } ) ;
2022-12-04 18:02:33 +00:00
return DeprecatedString : : formatted ( " {} {} " , op = = ProductOperation : : Multiply ? " * " sv : " / " sv , value_string ) ;
2022-02-02 15:34:13 +00:00
}
2022-12-06 01:12:49 +00:00
DeprecatedString CalculatedStyleValue : : CalcNumberProduct : : to_deprecated_string ( ) const
2022-02-02 15:34:13 +00:00
{
StringBuilder builder ;
2022-12-06 01:12:49 +00:00
builder . append ( first_calc_number_value . to_deprecated_string ( ) ) ;
2022-02-02 15:34:13 +00:00
for ( auto const & item : zero_or_more_additional_calc_number_values )
2022-12-06 01:12:49 +00:00
builder . append ( item . to_deprecated_string ( ) ) ;
return builder . to_deprecated_string ( ) ;
2022-02-02 15:34:13 +00:00
}
2022-12-06 01:12:49 +00:00
DeprecatedString CalculatedStyleValue : : CalcNumberProductPartWithOperator : : to_deprecated_string ( ) const
2022-02-02 15:34:13 +00:00
{
2022-12-06 01:12:49 +00:00
return DeprecatedString : : formatted ( " {} {} " , op = = ProductOperation : : Multiply ? " * " sv : " / " sv , value . to_deprecated_string ( ) ) ;
2022-02-02 15:34:13 +00:00
}
2022-12-06 01:12:49 +00:00
DeprecatedString CalculatedStyleValue : : CalcNumberSumPartWithOperator : : to_deprecated_string ( ) const
2022-02-02 15:34:13 +00:00
{
2022-12-06 01:12:49 +00:00
return DeprecatedString : : formatted ( " {} {} " , op = = SumOperation : : Add ? " + " sv : " - " sv , value - > to_deprecated_string ( ) ) ;
2022-02-02 15:34:13 +00:00
}
2022-02-21 17:43:30 +00:00
Optional < Angle > CalculatedStyleValue : : resolve_angle ( ) const
2022-01-24 17:38:29 +00:00
{
2022-02-21 17:43:30 +00:00
auto result = m_expression - > resolve ( nullptr , { } ) ;
if ( result . value ( ) . has < Angle > ( ) )
return result . value ( ) . get < Angle > ( ) ;
return { } ;
}
2022-07-20 13:03:30 +01:00
Optional < Angle > CalculatedStyleValue : : resolve_angle_percentage ( Angle const & percentage_basis ) const
2022-02-21 17:43:30 +00:00
{
auto result = m_expression - > resolve ( nullptr , percentage_basis ) ;
2022-01-24 17:38:29 +00:00
2022-01-27 14:51:51 +00:00
return result . value ( ) . visit (
2022-07-20 13:03:30 +01:00
[ & ] ( Angle const & angle ) - > Optional < Angle > {
2022-02-21 17:43:30 +00:00
return angle ;
2022-01-24 17:38:29 +00:00
} ,
2022-07-27 12:20:35 +01:00
[ & ] ( Percentage const & percentage ) - > Optional < Angle > {
return percentage_basis . percentage_of ( percentage ) ;
} ,
2022-07-20 13:03:30 +01:00
[ & ] ( auto const & ) - > Optional < Angle > {
2022-01-27 14:51:51 +00:00
return { } ;
2022-01-24 17:38:29 +00:00
} ) ;
}
2022-02-21 17:49:47 +00:00
Optional < Frequency > CalculatedStyleValue : : resolve_frequency ( ) const
{
auto result = m_expression - > resolve ( nullptr , { } ) ;
if ( result . value ( ) . has < Frequency > ( ) )
return result . value ( ) . get < Frequency > ( ) ;
return { } ;
}
2022-07-20 13:03:30 +01:00
Optional < Frequency > CalculatedStyleValue : : resolve_frequency_percentage ( Frequency const & percentage_basis ) const
2022-02-21 17:49:47 +00:00
{
auto result = m_expression - > resolve ( nullptr , percentage_basis ) ;
return result . value ( ) . visit (
2022-07-20 13:03:30 +01:00
[ & ] ( Frequency const & frequency ) - > Optional < Frequency > {
2022-02-21 17:49:47 +00:00
return frequency ;
} ,
2022-07-27 12:20:35 +01:00
[ & ] ( Percentage const & percentage ) - > Optional < Frequency > {
return percentage_basis . percentage_of ( percentage ) ;
} ,
2022-07-20 13:03:30 +01:00
[ & ] ( auto const & ) - > Optional < Frequency > {
2022-02-21 17:49:47 +00:00
return { } ;
} ) ;
}
2022-02-21 17:43:30 +00:00
Optional < Length > CalculatedStyleValue : : resolve_length ( Layout : : Node const & layout_node ) const
{
auto result = m_expression - > resolve ( & layout_node , { } ) ;
if ( result . value ( ) . has < Length > ( ) )
return result . value ( ) . get < Length > ( ) ;
return { } ;
}
2022-07-20 13:03:30 +01:00
Optional < Length > CalculatedStyleValue : : resolve_length_percentage ( Layout : : Node const & layout_node , Length const & percentage_basis ) const
2022-01-24 17:38:29 +00:00
{
2022-01-27 14:51:51 +00:00
auto result = m_expression - > resolve ( & layout_node , percentage_basis ) ;
2022-01-24 17:38:29 +00:00
2022-01-27 14:51:51 +00:00
return result . value ( ) . visit (
2022-07-20 13:03:30 +01:00
[ & ] ( Length const & length ) - > Optional < Length > {
2022-01-27 14:51:51 +00:00
return length ;
} ,
2022-07-27 12:20:35 +01:00
[ & ] ( Percentage const & percentage ) - > Optional < Length > {
return percentage_basis . percentage_of ( percentage ) ;
} ,
2022-07-20 13:03:30 +01:00
[ & ] ( auto const & ) - > Optional < Length > {
2022-02-21 17:43:30 +00:00
return { } ;
2022-01-24 17:38:29 +00:00
} ) ;
}
2022-01-27 15:46:24 +00:00
Optional < Percentage > CalculatedStyleValue : : resolve_percentage ( ) const
{
auto result = m_expression - > resolve ( nullptr , { } ) ;
if ( result . value ( ) . has < Percentage > ( ) )
return result . value ( ) . get < Percentage > ( ) ;
return { } ;
}
2022-02-21 19:29:43 +00:00
Optional < Time > CalculatedStyleValue : : resolve_time ( ) const
{
auto result = m_expression - > resolve ( nullptr , { } ) ;
if ( result . value ( ) . has < Time > ( ) )
return result . value ( ) . get < Time > ( ) ;
return { } ;
}
2022-07-20 13:03:30 +01:00
Optional < Time > CalculatedStyleValue : : resolve_time_percentage ( Time const & percentage_basis ) const
2022-02-21 19:29:43 +00:00
{
auto result = m_expression - > resolve ( nullptr , percentage_basis ) ;
return result . value ( ) . visit (
2022-07-20 13:03:30 +01:00
[ & ] ( Time const & time ) - > Optional < Time > {
2022-02-21 19:29:43 +00:00
return time ;
} ,
2022-07-20 13:03:30 +01:00
[ & ] ( auto const & ) - > Optional < Time > {
2022-02-21 19:29:43 +00:00
return { } ;
} ) ;
}
2022-01-27 15:46:24 +00:00
Optional < float > CalculatedStyleValue : : resolve_number ( )
{
auto result = m_expression - > resolve ( nullptr , { } ) ;
2022-02-02 12:34:32 +00:00
if ( result . value ( ) . has < Number > ( ) )
2022-03-21 21:03:17 +00:00
return result . value ( ) . get < Number > ( ) . value ( ) ;
2022-01-27 15:46:24 +00:00
return { } ;
}
Optional < i64 > CalculatedStyleValue : : resolve_integer ( )
{
auto result = m_expression - > resolve ( nullptr , { } ) ;
2022-02-02 12:34:32 +00:00
if ( result . value ( ) . has < Number > ( ) )
2022-03-21 21:03:17 +00:00
return result . value ( ) . get < Number > ( ) . integer_value ( ) ;
2022-01-27 15:46:24 +00:00
return { } ;
}
2022-01-25 14:45:08 +00: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 ;
}
template < typename SumWithOperator >
static Optional < CalculatedStyleValue : : ResolvedType > resolve_sum_type ( CalculatedStyleValue : : ResolvedType first_type , NonnullOwnPtrVector < SumWithOperator > const & zero_or_more_additional_products )
{
auto type = first_type ;
for ( auto const & product : zero_or_more_additional_products ) {
auto maybe_product_type = product . resolved_type ( ) ;
if ( ! maybe_product_type . has_value ( ) )
return { } ;
auto product_type = maybe_product_type . value ( ) ;
// 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 ( product_type = = type )
continue ;
// If one side is a <number> and the other is an <integer>, resolve to <number>.
if ( is_number ( type ) & & is_number ( product_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 ( product_type ) ) {
type = product_type ;
continue ;
}
if ( is_dimension ( type ) & & product_type = = CalculatedStyleValue : : ResolvedType : : Percentage )
continue ;
return { } ;
}
return type ;
}
Optional < CalculatedStyleValue : : ResolvedType > CalculatedStyleValue : : CalcSum : : resolved_type ( ) const
{
auto maybe_type = first_calc_product - > resolved_type ( ) ;
if ( ! maybe_type . has_value ( ) )
return { } ;
auto type = maybe_type . value ( ) ;
return resolve_sum_type ( type , zero_or_more_additional_calc_products ) ;
}
2022-08-02 15:08:06 +02:00
// https://www.w3.org/TR/CSS2/visufx.html#value-def-shape
Gfx : : FloatRect EdgeRect : : resolved ( Layout : : Node const & layout_node , Gfx : : FloatRect border_box ) const
{
// In CSS 2.1, the only valid <shape> value is: rect(<top>, <right>, <bottom>, <left>) where
// <top> and <bottom> specify offsets from the top border edge of the box, and <right>, and
// <left> specify offsets from the left border edge of the box.
// The value 'auto' means that a given edge of the clipping region will be the same as the edge
// of the element's generated border box (i.e., 'auto' means the same as '0' for <top> and
// <left>, the same as the used value of the height plus the sum of vertical padding and border
// widths for <bottom>, and the same as the used value of the width plus the sum of the
// horizontal padding and border widths for <right>, such that four 'auto' values result in the
// clipping region being the same as the element's border box).
2022-08-07 23:28:14 +01:00
auto left = border_box . left ( ) + ( left_edge . is_auto ( ) ? 0 : left_edge . to_px ( layout_node ) ) ;
auto top = border_box . top ( ) + ( top_edge . is_auto ( ) ? 0 : top_edge . to_px ( layout_node ) ) ;
auto right = border_box . left ( ) + ( right_edge . is_auto ( ) ? border_box . width ( ) : right_edge . to_px ( layout_node ) ) ;
auto bottom = border_box . top ( ) + ( bottom_edge . is_auto ( ) ? border_box . height ( ) : bottom_edge . to_px ( layout_node ) ) ;
2022-08-02 15:08:06 +02:00
return Gfx : : FloatRect {
2022-08-07 23:28:14 +01:00
left ,
top ,
right - left ,
bottom - top
2022-08-02 15:08:06 +02:00
} ;
}
2022-01-25 14:45:08 +00:00
Optional < CalculatedStyleValue : : ResolvedType > CalculatedStyleValue : : CalcNumberSum : : resolved_type ( ) const
{
auto maybe_type = first_calc_number_product - > resolved_type ( ) ;
if ( ! maybe_type . has_value ( ) )
return { } ;
auto type = maybe_type . value ( ) ;
return resolve_sum_type ( type , zero_or_more_additional_calc_number_products ) ;
}
template < typename ProductWithOperator >
static Optional < CalculatedStyleValue : : ResolvedType > resolve_product_type ( CalculatedStyleValue : : ResolvedType first_type , NonnullOwnPtrVector < ProductWithOperator > const & zero_or_more_additional_values )
{
auto type = first_type ;
for ( auto const & value : zero_or_more_additional_values ) {
auto maybe_value_type = value . resolved_type ( ) ;
if ( ! maybe_value_type . has_value ( ) )
return { } ;
auto value_type = maybe_value_type . value ( ) ;
if ( value . op = = CalculatedStyleValue : : ProductOperation : : Multiply ) {
// 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 ;
}
continue ;
} else {
VERIFY ( value . op = = CalculatedStyleValue : : ProductOperation : : Divide ) ;
// At /, check that the right side is <number>.
if ( ! is_number ( value_type ) )
return { } ;
// If the left side is <integer>, resolve to <number>.
if ( type = = CalculatedStyleValue : : ResolvedType : : Integer ) {
type = CalculatedStyleValue : : ResolvedType : : Number ;
} else {
// Otherwise, resolve to the type of the left side.
}
// FIXME: Division by zero makes the whole calc() expression invalid.
}
}
return type ;
}
Optional < CalculatedStyleValue : : ResolvedType > CalculatedStyleValue : : CalcProduct : : resolved_type ( ) const
{
auto maybe_type = first_calc_value . resolved_type ( ) ;
if ( ! maybe_type . has_value ( ) )
return { } ;
auto type = maybe_type . value ( ) ;
return resolve_product_type ( type , zero_or_more_additional_calc_values ) ;
}
Optional < CalculatedStyleValue : : ResolvedType > CalculatedStyleValue : : CalcSumPartWithOperator : : resolved_type ( ) const
{
return value - > resolved_type ( ) ;
}
Optional < CalculatedStyleValue : : ResolvedType > CalculatedStyleValue : : CalcNumberProduct : : resolved_type ( ) const
{
auto maybe_type = first_calc_number_value . resolved_type ( ) ;
if ( ! maybe_type . has_value ( ) )
return { } ;
auto type = maybe_type . value ( ) ;
return resolve_product_type ( type , zero_or_more_additional_calc_number_values ) ;
}
Optional < CalculatedStyleValue : : ResolvedType > CalculatedStyleValue : : CalcNumberProductPartWithOperator : : resolved_type ( ) const
{
return value . resolved_type ( ) ;
}
Optional < CalculatedStyleValue : : ResolvedType > CalculatedStyleValue : : CalcNumberSumPartWithOperator : : resolved_type ( ) const
{
return value - > resolved_type ( ) ;
}
Optional < CalculatedStyleValue : : ResolvedType > CalculatedStyleValue : : CalcProductPartWithOperator : : resolved_type ( ) const
{
return value . visit (
[ ] ( CalcValue const & calc_value ) {
return calc_value . resolved_type ( ) ;
} ,
[ ] ( CalcNumberValue const & calc_number_value ) {
return calc_number_value . resolved_type ( ) ;
} ) ;
}
Optional < CalculatedStyleValue : : ResolvedType > CalculatedStyleValue : : CalcValue : : resolved_type ( ) const
{
return value . visit (
2022-02-02 12:34:32 +00:00
[ ] ( Number const & number ) - > Optional < CalculatedStyleValue : : ResolvedType > {
2022-03-21 21:03:17 +00:00
return { number . is_integer ( ) ? ResolvedType : : Integer : ResolvedType : : Number } ;
2022-02-02 12:34:32 +00:00
} ,
2022-02-21 17:43:30 +00:00
[ ] ( Angle const & ) - > Optional < CalculatedStyleValue : : ResolvedType > { return { ResolvedType : : Angle } ; } ,
2022-02-21 17:49:47 +00:00
[ ] ( Frequency const & ) - > Optional < CalculatedStyleValue : : ResolvedType > { return { ResolvedType : : Frequency } ; } ,
2022-01-25 14:45:08 +00:00
[ ] ( Length const & ) - > Optional < CalculatedStyleValue : : ResolvedType > { return { ResolvedType : : Length } ; } ,
2022-01-27 14:47:39 +00:00
[ ] ( Percentage const & ) - > Optional < CalculatedStyleValue : : ResolvedType > { return { ResolvedType : : Percentage } ; } ,
2022-02-21 19:29:43 +00:00
[ ] ( Time const & ) - > Optional < CalculatedStyleValue : : ResolvedType > { return { ResolvedType : : Time } ; } ,
2022-01-25 14:45:08 +00:00
[ ] ( NonnullOwnPtr < CalcSum > const & sum ) { return sum - > resolved_type ( ) ; } ) ;
}
Optional < CalculatedStyleValue : : ResolvedType > CalculatedStyleValue : : CalcNumberValue : : resolved_type ( ) const
{
return value . visit (
2022-02-02 12:34:32 +00:00
[ ] ( Number const & number ) - > Optional < CalculatedStyleValue : : ResolvedType > {
2022-03-21 21:03:17 +00:00
return { number . is_integer ( ) ? ResolvedType : : Integer : ResolvedType : : Number } ;
2022-02-02 12:34:32 +00:00
} ,
2022-01-25 14:45:08 +00:00
[ ] ( NonnullOwnPtr < CalcNumberSum > const & sum ) { return sum - > resolved_type ( ) ; } ) ;
}
2022-02-18 12:07:09 +00:00
CalculatedStyleValue : : CalculationResult CalculatedStyleValue : : CalcNumberValue : : resolve ( Layout : : Node const * layout_node , PercentageBasis const & percentage_basis ) const
2022-01-27 14:51:51 +00:00
{
return value . visit (
2022-02-02 12:34:32 +00:00
[ & ] ( Number const & number ) - > CalculatedStyleValue : : CalculationResult {
return CalculatedStyleValue : : CalculationResult { number } ;
2022-01-27 14:51:51 +00:00
} ,
[ & ] ( NonnullOwnPtr < CalcNumberSum > const & sum ) - > CalculatedStyleValue : : CalculationResult {
return sum - > resolve ( layout_node , percentage_basis ) ;
} ) ;
}
2022-02-18 12:07:09 +00:00
CalculatedStyleValue : : CalculationResult CalculatedStyleValue : : CalcValue : : resolve ( Layout : : Node const * layout_node , PercentageBasis const & percentage_basis ) const
2022-01-27 14:51:51 +00:00
{
return value . visit (
[ & ] ( NonnullOwnPtr < CalcSum > const & sum ) - > CalculatedStyleValue : : CalculationResult {
return sum - > resolve ( layout_node , percentage_basis ) ;
2022-02-21 17:43:30 +00:00
} ,
[ & ] ( auto const & v ) - > CalculatedStyleValue : : CalculationResult {
return CalculatedStyleValue : : CalculationResult { v } ;
2022-01-27 14:51:51 +00:00
} ) ;
}
2022-02-18 12:07:09 +00:00
CalculatedStyleValue : : CalculationResult CalculatedStyleValue : : CalcSum : : resolve ( Layout : : Node const * layout_node , PercentageBasis const & percentage_basis ) const
2022-01-27 14:51:51 +00:00
{
auto value = first_calc_product - > resolve ( layout_node , percentage_basis ) ;
for ( auto & additional_product : zero_or_more_additional_calc_products ) {
auto additional_value = additional_product . resolve ( layout_node , percentage_basis ) ;
if ( additional_product . op = = CalculatedStyleValue : : SumOperation : : Add )
value . add ( additional_value , layout_node , percentage_basis ) ;
else if ( additional_product . op = = CalculatedStyleValue : : SumOperation : : Subtract )
value . subtract ( additional_value , layout_node , percentage_basis ) ;
else
VERIFY_NOT_REACHED ( ) ;
}
return value ;
}
2022-02-18 12:07:09 +00:00
CalculatedStyleValue : : CalculationResult CalculatedStyleValue : : CalcNumberSum : : resolve ( Layout : : Node const * layout_node , PercentageBasis const & percentage_basis ) const
2022-01-27 14:51:51 +00:00
{
auto value = first_calc_number_product - > resolve ( layout_node , percentage_basis ) ;
for ( auto & additional_product : zero_or_more_additional_calc_number_products ) {
auto additional_value = additional_product . resolve ( layout_node , percentage_basis ) ;
if ( additional_product . op = = CSS : : CalculatedStyleValue : : SumOperation : : Add )
value . add ( additional_value , layout_node , percentage_basis ) ;
else if ( additional_product . op = = CalculatedStyleValue : : SumOperation : : Subtract )
value . subtract ( additional_value , layout_node , percentage_basis ) ;
else
VERIFY_NOT_REACHED ( ) ;
}
return value ;
}
2022-02-18 12:07:09 +00:00
CalculatedStyleValue : : CalculationResult CalculatedStyleValue : : CalcProduct : : resolve ( Layout : : Node const * layout_node , PercentageBasis const & percentage_basis ) const
2022-01-27 14:51:51 +00:00
{
auto value = first_calc_value . resolve ( layout_node , percentage_basis ) ;
for ( auto & additional_value : zero_or_more_additional_calc_values ) {
additional_value . value . visit (
[ & ] ( CalculatedStyleValue : : CalcValue const & calc_value ) {
VERIFY ( additional_value . op = = CalculatedStyleValue : : ProductOperation : : Multiply ) ;
auto resolved_value = calc_value . resolve ( layout_node , percentage_basis ) ;
value . multiply_by ( resolved_value , layout_node ) ;
} ,
[ & ] ( CalculatedStyleValue : : CalcNumberValue const & calc_number_value ) {
VERIFY ( additional_value . op = = CalculatedStyleValue : : ProductOperation : : Divide ) ;
auto resolved_calc_number_value = calc_number_value . resolve ( layout_node , percentage_basis ) ;
2022-02-02 12:34:32 +00:00
// FIXME: Checking for division by 0 should happen during parsing.
2022-03-21 21:03:17 +00:00
VERIFY ( resolved_calc_number_value . value ( ) . get < Number > ( ) . value ( ) ! = 0.0f ) ;
2022-01-27 14:51:51 +00:00
value . divide_by ( resolved_calc_number_value , layout_node ) ;
} ) ;
}
return value ;
}
2022-02-18 12:07:09 +00:00
CalculatedStyleValue : : CalculationResult CalculatedStyleValue : : CalcNumberProduct : : resolve ( Layout : : Node const * layout_node , PercentageBasis const & percentage_basis ) const
2022-01-27 14:51:51 +00:00
{
auto value = first_calc_number_value . resolve ( layout_node , percentage_basis ) ;
for ( auto & additional_number_value : zero_or_more_additional_calc_number_values ) {
auto additional_value = additional_number_value . resolve ( layout_node , percentage_basis ) ;
if ( additional_number_value . op = = CalculatedStyleValue : : ProductOperation : : Multiply )
value . multiply_by ( additional_value , layout_node ) ;
else if ( additional_number_value . op = = CalculatedStyleValue : : ProductOperation : : Divide )
value . divide_by ( additional_value , layout_node ) ;
else
VERIFY_NOT_REACHED ( ) ;
}
return value ;
}
2022-02-18 12:07:09 +00:00
CalculatedStyleValue : : CalculationResult CalculatedStyleValue : : CalcProductPartWithOperator : : resolve ( Layout : : Node const * layout_node , PercentageBasis const & percentage_basis ) const
2022-01-27 14:51:51 +00:00
{
return value . visit (
[ & ] ( CalcValue const & calc_value ) {
return calc_value . resolve ( layout_node , percentage_basis ) ;
} ,
[ & ] ( CalcNumberValue const & calc_number_value ) {
return calc_number_value . resolve ( layout_node , percentage_basis ) ;
} ) ;
}
2022-02-18 12:07:09 +00:00
CalculatedStyleValue : : CalculationResult CalculatedStyleValue : : CalcSumPartWithOperator : : resolve ( Layout : : Node const * layout_node , PercentageBasis const & percentage_basis ) const
2022-01-27 14:51:51 +00:00
{
return value - > resolve ( layout_node , percentage_basis ) ;
}
2022-02-18 12:07:09 +00:00
CalculatedStyleValue : : CalculationResult CalculatedStyleValue : : CalcNumberProductPartWithOperator : : resolve ( Layout : : Node const * layout_node , PercentageBasis const & percentage_basis ) const
2022-01-27 14:51:51 +00:00
{
return value . resolve ( layout_node , percentage_basis ) ;
}
2022-02-18 12:07:09 +00:00
CalculatedStyleValue : : CalculationResult CalculatedStyleValue : : CalcNumberSumPartWithOperator : : resolve ( Layout : : Node const * layout_node , PercentageBasis const & percentage_basis ) const
2022-01-27 14:51:51 +00:00
{
return value - > resolve ( layout_node , percentage_basis ) ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString ColorStyleValue : : to_deprecated_string ( ) const
2022-02-02 20:39:04 +00:00
{
2022-07-12 15:30:13 +01:00
return serialize_a_srgb_value ( m_color ) ;
2022-02-02 20:39:04 +00:00
}
2022-04-18 17:42:03 +01:00
bool ColorStyleValue : : equals ( StyleValue const & other ) const
2022-02-02 20:39:04 +00:00
{
2022-04-18 17:42:03 +01:00
if ( type ( ) ! = other . type ( ) )
return false ;
return m_color = = other . as_color ( ) . m_color ;
2022-02-02 20:39:04 +00:00
}
2022-12-06 01:12:49 +00:00
DeprecatedString ContentStyleValue : : to_deprecated_string ( ) const
2022-02-23 19:56:25 +00:00
{
if ( has_alt_text ( ) )
2022-12-06 01:12:49 +00:00
return DeprecatedString : : formatted ( " {} / {} " , m_content - > to_deprecated_string ( ) , m_alt_text - > to_deprecated_string ( ) ) ;
return m_content - > to_deprecated_string ( ) ;
2022-02-23 19:56:25 +00:00
}
2022-04-18 17:42:03 +01:00
bool ContentStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_content ( ) ;
if ( ! m_content - > equals ( typed_other . m_content ) )
return false ;
if ( m_alt_text . is_null ( ) ! = typed_other . m_alt_text . is_null ( ) )
return false ;
if ( ! m_alt_text . is_null ( ) )
return m_alt_text - > equals ( * typed_other . m_alt_text ) ;
return true ;
}
2022-09-15 08:31:14 +01:00
float Filter : : Blur : : resolved_radius ( Layout : : Node const & node ) const
{
// Default value when omitted is 0px.
auto sigma = 0 ;
if ( radius . has_value ( ) )
sigma = radius - > resolved ( node ) . to_px ( node ) ;
// Note: The radius/sigma of the blur needs to be doubled for LibGfx's blur functions.
return sigma * 2 ;
}
Filter : : DropShadow : : Resolved Filter : : DropShadow : : resolved ( Layout : : Node const & node ) const
{
// The default value for omitted values is missing length values set to 0
// and the missing used color is taken from the color property.
return Resolved {
offset_x . resolved ( node ) . to_px ( node ) ,
offset_y . resolved ( node ) . to_px ( node ) ,
radius . has_value ( ) ? radius - > resolved ( node ) . to_px ( node ) : 0.0f ,
color . has_value ( ) ? * color : node . computed_values ( ) . color ( )
} ;
}
float Filter : : HueRotate : : angle_degrees ( ) const
{
// Default value when omitted is 0deg.
if ( ! angle . has_value ( ) )
return 0.0f ;
return angle - > visit ( [ & ] ( Angle const & angle ) { return angle . to_degrees ( ) ; } , [ & ] ( auto ) { return 0.0f ; } ) ;
}
float Filter : : Color : : resolved_amount ( ) const
{
if ( amount . has_value ( ) ) {
if ( amount - > is_percentage ( ) )
return amount - > percentage ( ) . as_fraction ( ) ;
return amount - > number ( ) . value ( ) ;
}
// All color filters (brightness, sepia, etc) have a default amount of 1.
return 1.0f ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString FilterValueListStyleValue : : to_deprecated_string ( ) const
2022-09-15 08:31:14 +01:00
{
StringBuilder builder { } ;
bool first = true ;
for ( auto & filter_function : filter_value_list ( ) ) {
if ( ! first )
builder . append ( ' ' ) ;
filter_function . visit (
[ & ] ( Filter : : Blur const & blur ) {
builder . append ( " blur( " sv ) ;
if ( blur . radius . has_value ( ) )
2022-12-06 01:12:49 +00:00
builder . append ( blur . radius - > to_deprecated_string ( ) ) ;
2022-09-15 08:31:14 +01:00
} ,
[ & ] ( Filter : : DropShadow const & drop_shadow ) {
builder . appendff ( " drop-shadow({} {} " sv ,
drop_shadow . offset_x , drop_shadow . offset_y ) ;
if ( drop_shadow . radius . has_value ( ) )
2022-12-06 01:12:49 +00:00
builder . appendff ( " {} " , drop_shadow . radius - > to_deprecated_string ( ) ) ;
2022-09-15 08:31:14 +01:00
if ( drop_shadow . color . has_value ( ) ) {
builder . append ( ' ' ) ;
serialize_a_srgb_value ( builder , * drop_shadow . color ) ;
}
} ,
[ & ] ( Filter : : HueRotate const & hue_rotate ) {
builder . append ( " hue-rotate( " sv ) ;
if ( hue_rotate . angle . has_value ( ) ) {
hue_rotate . angle - > visit (
[ & ] ( Angle const & angle ) {
2022-12-06 01:12:49 +00:00
builder . append ( angle . to_deprecated_string ( ) ) ;
2022-09-15 08:31:14 +01:00
} ,
[ & ] ( auto & ) {
builder . append ( ' 0 ' ) ;
} ) ;
}
} ,
[ & ] ( Filter : : Color const & color ) {
builder . appendff ( " {}( " ,
[ & ] {
switch ( color . operation ) {
case Filter : : Color : : Operation : : Brightness :
return " brightness " sv ;
case Filter : : Color : : Operation : : Contrast :
return " contrast " sv ;
case Filter : : Color : : Operation : : Grayscale :
return " grayscale " sv ;
case Filter : : Color : : Operation : : Invert :
return " invert " sv ;
case Filter : : Color : : Operation : : Opacity :
return " opacity " sv ;
case Filter : : Color : : Operation : : Saturate :
return " saturate " sv ;
case Filter : : Color : : Operation : : Sepia :
return " sepia " sv ;
default :
VERIFY_NOT_REACHED ( ) ;
}
} ( ) ) ;
if ( color . amount . has_value ( ) )
2022-12-06 01:12:49 +00:00
builder . append ( color . amount - > to_deprecated_string ( ) ) ;
2022-09-15 08:31:14 +01:00
} ) ;
builder . append ( ' ) ' ) ;
first = false ;
}
2022-12-06 01:12:49 +00:00
return builder . to_deprecated_string ( ) ;
2022-09-15 08:31:14 +01:00
}
static bool operator = = ( Filter : : Blur const & a , Filter : : Blur const & b )
{
return a . radius = = b . radius ;
}
static bool operator = = ( Filter : : DropShadow const & a , Filter : : DropShadow const & b )
{
return a . offset_x = = b . offset_x & & a . offset_y = = b . offset_y & & a . radius = = b . radius & & a . color = = b . color ;
}
static bool operator = = ( Filter : : HueRotate : : Zero const & , Filter : : HueRotate : : Zero const & )
{
return true ;
}
static bool operator = = ( Filter : : Color const & a , Filter : : Color const & b )
{
return a . operation = = b . operation & & a . amount = = b . amount ;
}
static bool operator = = ( Filter : : HueRotate const & a , Filter : : HueRotate const & b )
{
return a . angle = = b . angle ;
}
static bool variant_equals ( auto const & a , auto const & b )
{
return a . visit ( [ & ] ( auto const & held_value ) {
using HeldType = AK : : Detail : : Decay < decltype ( held_value ) > ;
bool other_holds_same_type = b . template has < HeldType > ( ) ;
return other_holds_same_type & & held_value = = b . template get < HeldType > ( ) ;
} ) ;
}
static bool operator = = ( Filter : : HueRotate : : AngleOrZero const & a , Filter : : HueRotate : : AngleOrZero const & b )
{
return variant_equals ( a , b ) ;
}
static bool operator = = ( FilterFunction const & a , FilterFunction const & b )
{
return variant_equals ( a , b ) ;
}
bool FilterValueListStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_filter_value_list ( ) ;
if ( m_filter_value_list . size ( ) ! = typed_other . m_filter_value_list . size ( ) )
return false ;
for ( size_t i = 0 ; i < m_filter_value_list . size ( ) ; i + + ) {
if ( m_filter_value_list [ i ] ! = typed_other . m_filter_value_list [ i ] )
return false ;
}
return true ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString FlexStyleValue : : to_deprecated_string ( ) const
2022-02-02 20:39:04 +00:00
{
2022-12-06 01:12:49 +00:00
return DeprecatedString : : formatted ( " {} {} {} " , m_grow - > to_deprecated_string ( ) , m_shrink - > to_deprecated_string ( ) , m_basis - > to_deprecated_string ( ) ) ;
2022-02-02 20:39:04 +00:00
}
2022-04-18 17:42:03 +01:00
bool FlexStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_flex ( ) ;
return m_grow - > equals ( typed_other . m_grow )
& & m_shrink - > equals ( typed_other . m_shrink )
& & m_basis - > equals ( typed_other . m_basis ) ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString FlexFlowStyleValue : : to_deprecated_string ( ) const
2022-02-02 20:39:04 +00:00
{
2022-12-06 01:12:49 +00:00
return DeprecatedString : : formatted ( " {} {} " , m_flex_direction - > to_deprecated_string ( ) , m_flex_wrap - > to_deprecated_string ( ) ) ;
2022-02-02 20:39:04 +00:00
}
2022-04-18 17:42:03 +01:00
bool FlexFlowStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_flex_flow ( ) ;
return m_flex_direction - > equals ( typed_other . m_flex_direction )
& & m_flex_wrap - > equals ( typed_other . m_flex_wrap ) ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString FontStyleValue : : to_deprecated_string ( ) const
2022-02-02 20:39:04 +00:00
{
2022-12-06 01:12:49 +00:00
return DeprecatedString : : formatted ( " {} {} {} / {} {} " , m_font_style - > to_deprecated_string ( ) , m_font_weight - > to_deprecated_string ( ) , m_font_size - > to_deprecated_string ( ) , m_line_height - > to_deprecated_string ( ) , m_font_families - > to_deprecated_string ( ) ) ;
2022-02-02 20:39:04 +00:00
}
2022-04-18 17:42:03 +01:00
bool FontStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_font ( ) ;
return m_font_style - > equals ( typed_other . m_font_style )
& & m_font_weight - > equals ( typed_other . m_font_weight )
& & m_font_size - > equals ( typed_other . m_font_size )
& & m_line_height - > equals ( typed_other . m_line_height )
& & m_font_families - > equals ( typed_other . m_font_families ) ;
}
bool FrequencyStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
return m_frequency = = other . as_frequency ( ) . m_frequency ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString GridTrackPlacementShorthandStyleValue : : to_deprecated_string ( ) const
2022-08-24 12:25:56 +02:00
{
2022-09-17 16:54:39 +02:00
if ( m_end - > grid_track_placement ( ) . is_auto ( ) )
2022-12-06 01:12:49 +00:00
return DeprecatedString : : formatted ( " {} " , m_start - > grid_track_placement ( ) . to_deprecated_string ( ) ) ;
return DeprecatedString : : formatted ( " {} / {} " , m_start - > grid_track_placement ( ) . to_deprecated_string ( ) , m_end - > grid_track_placement ( ) . to_deprecated_string ( ) ) ;
2022-08-24 12:25:56 +02:00
}
bool GridTrackPlacementShorthandStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_grid_track_placement_shorthand ( ) ;
return m_start - > equals ( typed_other . m_start )
& & m_end - > equals ( typed_other . m_end ) ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString GridTrackPlacementStyleValue : : to_deprecated_string ( ) const
2022-08-24 12:31:00 +02:00
{
2022-12-06 01:12:49 +00:00
return m_grid_track_placement . to_deprecated_string ( ) ;
2022-08-24 12:31:00 +02:00
}
bool GridTrackPlacementStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_grid_track_placement ( ) ;
return m_grid_track_placement = = typed_other . grid_track_placement ( ) ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString GridTrackSizeStyleValue : : to_deprecated_string ( ) const
2022-08-24 12:27:56 +02:00
{
2022-12-06 01:12:49 +00:00
return m_grid_track_size_list . to_deprecated_string ( ) ;
2022-08-24 12:27:56 +02:00
}
bool GridTrackSizeStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
2022-10-30 13:27:57 +01:00
auto const & typed_other = other . as_grid_track_size_list ( ) ;
return m_grid_track_size_list = = typed_other . grid_track_size_list ( ) ;
2022-08-24 12:27:56 +02:00
}
2022-12-06 01:12:49 +00:00
DeprecatedString IdentifierStyleValue : : to_deprecated_string ( ) const
2021-09-23 19:54:19 +01:00
{
return CSS : : string_from_value_id ( m_id ) ;
}
2022-04-18 17:42:03 +01:00
bool IdentifierStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
return m_id = = other . as_identifier ( ) . m_id ;
}
2021-09-23 19:54:19 +01:00
bool IdentifierStyleValue : : has_color ( ) const
{
switch ( m_id ) {
2021-09-22 12:42:54 +01:00
case ValueID : : Currentcolor :
case ValueID : : LibwebLink :
case ValueID : : LibwebPaletteActiveLink :
case ValueID : : LibwebPaletteActiveWindowBorder1 :
case ValueID : : LibwebPaletteActiveWindowBorder2 :
case ValueID : : LibwebPaletteActiveWindowTitle :
case ValueID : : LibwebPaletteBase :
case ValueID : : LibwebPaletteBaseText :
case ValueID : : LibwebPaletteButton :
case ValueID : : LibwebPaletteButtonText :
case ValueID : : LibwebPaletteDesktopBackground :
case ValueID : : LibwebPaletteFocusOutline :
case ValueID : : LibwebPaletteHighlightWindowBorder1 :
case ValueID : : LibwebPaletteHighlightWindowBorder2 :
case ValueID : : LibwebPaletteHighlightWindowTitle :
case ValueID : : LibwebPaletteHoverHighlight :
case ValueID : : LibwebPaletteInactiveSelection :
case ValueID : : LibwebPaletteInactiveSelectionText :
case ValueID : : LibwebPaletteInactiveWindowBorder1 :
case ValueID : : LibwebPaletteInactiveWindowBorder2 :
case ValueID : : LibwebPaletteInactiveWindowTitle :
case ValueID : : LibwebPaletteLink :
case ValueID : : LibwebPaletteMenuBase :
case ValueID : : LibwebPaletteMenuBaseText :
case ValueID : : LibwebPaletteMenuSelection :
case ValueID : : LibwebPaletteMenuSelectionText :
case ValueID : : LibwebPaletteMenuStripe :
case ValueID : : LibwebPaletteMovingWindowBorder1 :
case ValueID : : LibwebPaletteMovingWindowBorder2 :
case ValueID : : LibwebPaletteMovingWindowTitle :
case ValueID : : LibwebPaletteRubberBandBorder :
case ValueID : : LibwebPaletteRubberBandFill :
case ValueID : : LibwebPaletteRuler :
case ValueID : : LibwebPaletteRulerActiveText :
case ValueID : : LibwebPaletteRulerBorder :
case ValueID : : LibwebPaletteRulerInactiveText :
case ValueID : : LibwebPaletteSelection :
case ValueID : : LibwebPaletteSelectionText :
case ValueID : : LibwebPaletteSyntaxComment :
case ValueID : : LibwebPaletteSyntaxControlKeyword :
case ValueID : : LibwebPaletteSyntaxIdentifier :
case ValueID : : LibwebPaletteSyntaxKeyword :
case ValueID : : LibwebPaletteSyntaxNumber :
case ValueID : : LibwebPaletteSyntaxOperator :
case ValueID : : LibwebPaletteSyntaxPreprocessorStatement :
case ValueID : : LibwebPaletteSyntaxPreprocessorValue :
case ValueID : : LibwebPaletteSyntaxPunctuation :
case ValueID : : LibwebPaletteSyntaxString :
case ValueID : : LibwebPaletteSyntaxType :
case ValueID : : LibwebPaletteTextCursor :
case ValueID : : LibwebPaletteThreedHighlight :
case ValueID : : LibwebPaletteThreedShadow1 :
case ValueID : : LibwebPaletteThreedShadow2 :
case ValueID : : LibwebPaletteVisitedLink :
case ValueID : : LibwebPaletteWindow :
case ValueID : : LibwebPaletteWindowText :
return true ;
default :
2021-09-23 19:54:19 +01:00
return false ;
2021-09-22 12:42:54 +01:00
}
2019-10-06 10:25:08 +02:00
}
2021-09-16 19:20:20 +01:00
Color IdentifierStyleValue : : to_color ( Layout : : NodeWithStyle const & node ) const
2019-10-06 10:25:08 +02:00
{
2021-09-16 19:40:56 +01:00
if ( id ( ) = = CSS : : ValueID : : Currentcolor ) {
if ( ! node . has_style ( ) )
return Color : : Black ;
return node . computed_values ( ) . color ( ) ;
}
2021-09-16 19:20:20 +01:00
auto & document = node . document ( ) ;
2020-12-15 20:39:09 +01:00
if ( id ( ) = = CSS : : ValueID : : LibwebLink )
2019-10-06 10:25:08 +02:00
return document . link_color ( ) ;
2020-05-25 14:54:27 -04:00
2022-03-19 18:09:22 +01:00
if ( ! document . page ( ) )
return { } ;
2020-11-12 18:23:05 +01:00
auto palette = document . page ( ) - > palette ( ) ;
2020-05-25 14:54:27 -04:00
switch ( id ( ) ) {
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteDesktopBackground :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : DesktopBackground ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteActiveWindowBorder1 :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : ActiveWindowBorder1 ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteActiveWindowBorder2 :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : ActiveWindowBorder2 ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteActiveWindowTitle :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : ActiveWindowTitle ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteInactiveWindowBorder1 :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : InactiveWindowBorder1 ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteInactiveWindowBorder2 :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : InactiveWindowBorder2 ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteInactiveWindowTitle :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : InactiveWindowTitle ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteMovingWindowBorder1 :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : MovingWindowBorder1 ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteMovingWindowBorder2 :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : MovingWindowBorder2 ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteMovingWindowTitle :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : MovingWindowTitle ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteHighlightWindowBorder1 :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : HighlightWindowBorder1 ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteHighlightWindowBorder2 :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : HighlightWindowBorder2 ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteHighlightWindowTitle :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : HighlightWindowTitle ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteMenuStripe :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : MenuStripe ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteMenuBase :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : MenuBase ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteMenuBaseText :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : MenuBaseText ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteMenuSelection :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : MenuSelection ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteMenuSelectionText :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : MenuSelectionText ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteWindow :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : Window ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteWindowText :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : WindowText ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteButton :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : Button ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteButtonText :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : ButtonText ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteBase :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : Base ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteBaseText :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : BaseText ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteThreedHighlight :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : ThreedHighlight ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteThreedShadow1 :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : ThreedShadow1 ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteThreedShadow2 :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : ThreedShadow2 ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteHoverHighlight :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : HoverHighlight ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteSelection :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : Selection ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteSelectionText :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : SelectionText ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteInactiveSelection :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : InactiveSelection ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteInactiveSelectionText :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : InactiveSelectionText ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteRubberBandFill :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : RubberBandFill ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteRubberBandBorder :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : RubberBandBorder ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteLink :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : Link ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteActiveLink :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : ActiveLink ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteVisitedLink :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : VisitedLink ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteRuler :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : Ruler ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteRulerBorder :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : RulerBorder ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteRulerActiveText :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : RulerActiveText ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteRulerInactiveText :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : RulerInactiveText ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteTextCursor :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : TextCursor ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteFocusOutline :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : FocusOutline ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteSyntaxComment :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : SyntaxComment ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteSyntaxNumber :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : SyntaxNumber ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteSyntaxString :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : SyntaxString ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteSyntaxType :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : SyntaxType ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteSyntaxPunctuation :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : SyntaxPunctuation ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteSyntaxOperator :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : SyntaxOperator ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteSyntaxKeyword :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : SyntaxKeyword ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteSyntaxControlKeyword :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : SyntaxControlKeyword ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteSyntaxIdentifier :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : SyntaxIdentifier ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteSyntaxPreprocessorStatement :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : SyntaxPreprocessorStatement ) ;
2020-12-15 20:39:09 +01:00
case CSS : : ValueID : : LibwebPaletteSyntaxPreprocessorValue :
2020-05-25 14:54:27 -04:00
return palette . color ( ColorRole : : SyntaxPreprocessorValue ) ;
default :
return { } ;
}
2019-10-06 10:25:08 +02:00
}
2019-10-19 11:49:46 +02:00
2021-10-22 20:55:27 +01:00
ImageStyleValue : : ImageStyleValue ( AK : : URL const & url )
2022-07-31 01:11:59 +01:00
: AbstractImageStyleValue ( Type : : Image )
2019-10-19 11:49:46 +02:00
, m_url ( url )
{
2021-10-22 20:55:27 +01:00
}
2022-07-31 01:11:59 +01:00
void ImageStyleValue : : load_any_resources ( DOM : : Document & document )
2021-10-22 20:55:27 +01:00
{
2022-09-07 17:38:29 +02:00
if ( resource ( ) )
return ;
2021-10-22 20:55:27 +01:00
m_document = & document ;
auto request = LoadRequest : : create_for_url_on_page ( m_url , document . page ( ) ) ;
2020-06-05 23:32:23 +02:00
set_resource ( ResourceLoader : : the ( ) . load_resource ( Resource : : Type : : Image , request ) ) ;
2020-06-02 13:51:30 +02:00
}
void ImageStyleValue : : resource_did_load ( )
{
if ( ! m_document )
return ;
// FIXME: Do less than a full repaint if possible?
2021-09-30 02:18:30 +02:00
if ( m_document & & m_document - > browsing_context ( ) )
2022-06-30 20:03:55 +01:00
m_document - > browsing_context ( ) - > set_needs_display ( ) ;
2022-10-30 15:43:42 +00:00
if ( resource ( ) - > is_animated ( ) & & resource ( ) - > frame_count ( ) > 1 ) {
m_timer = Platform : : Timer : : create ( ) ;
m_timer - > set_interval ( resource ( ) - > frame_duration ( 0 ) ) ;
m_timer - > on_timeout = [ this ] { animate ( ) ; } ;
m_timer - > start ( ) ;
}
}
void ImageStyleValue : : animate ( )
{
m_current_frame_index = ( m_current_frame_index + 1 ) % resource ( ) - > frame_count ( ) ;
auto current_frame_duration = resource ( ) - > frame_duration ( m_current_frame_index ) ;
if ( current_frame_duration ! = m_timer - > interval ( ) )
m_timer - > restart ( current_frame_duration ) ;
if ( m_current_frame_index = = resource ( ) - > frame_count ( ) - 1 ) {
+ + m_loops_completed ;
if ( m_loops_completed > 0 & & m_loops_completed = = resource ( ) - > loop_count ( ) )
m_timer - > stop ( ) ;
}
if ( on_animate )
on_animate ( ) ;
}
Gfx : : Bitmap const * ImageStyleValue : : bitmap ( size_t frame_index ) const
{
if ( ! resource ( ) )
return nullptr ;
return resource ( ) - > bitmap ( frame_index ) ;
2019-10-19 11:49:46 +02:00
}
2021-10-03 17:56:01 +02:00
2022-12-06 01:12:49 +00:00
DeprecatedString ImageStyleValue : : to_deprecated_string ( ) const
2021-10-03 17:56:01 +02:00
{
2022-12-06 01:12:49 +00:00
return serialize_a_url ( m_url . to_deprecated_string ( ) ) ;
2022-02-02 20:39:04 +00:00
}
2022-04-18 17:42:03 +01:00
bool ImageStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
return m_url = = other . as_image ( ) . m_url ;
}
2022-07-31 01:11:59 +01:00
Optional < int > ImageStyleValue : : natural_width ( ) const
{
2022-11-16 20:00:49 +01:00
if ( auto * b = bitmap ( 0 ) ; b ! = nullptr )
return b - > width ( ) ;
2022-07-31 01:11:59 +01:00
return { } ;
}
Optional < int > ImageStyleValue : : natural_height ( ) const
{
2022-11-16 20:00:49 +01:00
if ( auto * b = bitmap ( 0 ) ; b ! = nullptr )
return b - > height ( ) ;
2022-07-31 01:11:59 +01:00
return { } ;
}
2022-08-10 16:16:46 +01:00
void ImageStyleValue : : paint ( PaintContext & context , Gfx : : IntRect const & dest_rect , CSS : : ImageRendering image_rendering ) const
2022-07-31 01:11:59 +01:00
{
2022-11-16 20:00:49 +01:00
if ( auto * b = bitmap ( m_current_frame_index ) ; b ! = nullptr )
context . painter ( ) . draw_scaled_bitmap ( dest_rect , * b , bitmap ( 0 ) - > rect ( ) , 1.0f , to_gfx_scaling_mode ( image_rendering ) ) ;
2022-07-31 01:11:59 +01:00
}
2022-10-28 20:44:00 +01:00
static void serialize_color_stop_list ( StringBuilder & builder , auto const & color_stop_list )
{
bool first = true ;
for ( auto const & element : color_stop_list ) {
if ( ! first )
builder . append ( " , " sv ) ;
if ( element . transition_hint . has_value ( ) ) {
2022-12-06 01:12:49 +00:00
builder . appendff ( " {}, " sv , element . transition_hint - > value . to_deprecated_string ( ) ) ;
2022-10-28 20:44:00 +01:00
}
serialize_a_srgb_value ( builder , element . color_stop . color ) ;
for ( auto position : Array { & element . color_stop . position , & element . color_stop . second_position } ) {
if ( position - > has_value ( ) )
2022-12-06 01:12:49 +00:00
builder . appendff ( " {} " sv , ( * position ) - > to_deprecated_string ( ) ) ;
2022-10-28 20:44:00 +01:00
}
first = false ;
}
}
2022-12-06 01:12:49 +00:00
DeprecatedString LinearGradientStyleValue : : to_deprecated_string ( ) const
2022-07-12 00:09:29 +01:00
{
StringBuilder builder ;
2022-12-06 01:12:49 +00:00
auto side_or_corner_to_deprecated_string = [ ] ( SideOrCorner value ) {
2022-07-12 00:09:29 +01:00
switch ( value ) {
case SideOrCorner : : Top :
return " top " sv ;
case SideOrCorner : : Bottom :
return " bottom " sv ;
case SideOrCorner : : Left :
return " left " sv ;
case SideOrCorner : : Right :
return " right " sv ;
case SideOrCorner : : TopLeft :
return " top left " sv ;
case SideOrCorner : : TopRight :
return " top right " sv ;
case SideOrCorner : : BottomLeft :
return " bottom left " sv ;
case SideOrCorner : : BottomRight :
return " bottom right " sv ;
default :
VERIFY_NOT_REACHED ( ) ;
}
} ;
2022-08-07 12:36:04 +01:00
if ( m_gradient_type = = GradientType : : WebKit )
builder . append ( " -webkit- " sv ) ;
2022-11-06 14:51:10 +00:00
if ( is_repeating ( ) )
2022-08-16 17:09:49 +01:00
builder . append ( " repeating- " sv ) ;
2022-07-12 00:09:29 +01:00
builder . append ( " linear-gradient( " sv ) ;
m_direction . visit (
[ & ] ( SideOrCorner side_or_corner ) {
2022-12-06 01:12:49 +00:00
builder . appendff ( " {}{}, " sv , m_gradient_type = = GradientType : : Standard ? " to " sv : " " sv , side_or_corner_to_deprecated_string ( side_or_corner ) ) ;
2022-07-12 00:09:29 +01:00
} ,
[ & ] ( Angle const & angle ) {
2022-12-06 01:12:49 +00:00
builder . appendff ( " {}, " sv , angle . to_deprecated_string ( ) ) ;
2022-07-12 00:09:29 +01:00
} ) ;
2022-10-28 20:44:00 +01:00
serialize_color_stop_list ( builder , m_color_stop_list ) ;
2022-07-12 00:09:29 +01:00
builder . append ( " ) " sv ) ;
2022-12-06 01:12:49 +00:00
return builder . to_deprecated_string ( ) ;
2022-07-12 00:09:29 +01:00
}
2022-09-15 08:31:01 +01:00
static bool operator = = ( LinearGradientStyleValue : : GradientDirection const & a , LinearGradientStyleValue : : GradientDirection const & b )
2022-07-12 00:09:29 +01:00
{
if ( a . has < SideOrCorner > ( ) & & b . has < SideOrCorner > ( ) )
return a . get < SideOrCorner > ( ) = = b . get < SideOrCorner > ( ) ;
if ( a . has < Angle > ( ) & & b . has < Angle > ( ) )
return a . get < Angle > ( ) = = b . get < Angle > ( ) ;
return false ;
}
2022-09-15 08:31:01 +01:00
static bool operator = = ( EdgeRect const & a , EdgeRect const & b )
2022-07-31 18:46:35 +02:00
{
return a . top_edge = = b . top_edge & & a . right_edge = = b . right_edge & & a . bottom_edge = = b . bottom_edge & & a . left_edge = = b . left_edge ;
}
2022-07-12 00:09:29 +01:00
bool LinearGradientStyleValue : : equals ( StyleValue const & other_ ) const
{
if ( type ( ) ! = other_ . type ( ) )
return false ;
auto & other = other_ . as_linear_gradient ( ) ;
2022-11-07 19:02:00 +01:00
return ( m_gradient_type = = other . m_gradient_type
& & m_repeating = = other . m_repeating
& & m_direction = = other . m_direction
& & m_color_stop_list = = other . m_color_stop_list ) ;
2022-07-12 00:09:29 +01:00
}
2022-12-06 21:44:49 +00:00
float LinearGradientStyleValue : : angle_degrees ( Gfx : : FloatSize gradient_size ) const
2022-07-12 00:09:29 +01:00
{
2022-07-17 19:45:38 +01:00
auto corner_angle_degrees = [ & ] {
2022-07-31 01:11:59 +01:00
return static_cast < float > ( atan2 ( gradient_size . height ( ) , gradient_size . width ( ) ) ) * 180 / AK : : Pi < float > ;
2022-07-17 19:45:38 +01:00
} ;
2022-07-12 00:09:29 +01:00
return m_direction . visit (
[ & ] ( SideOrCorner side_or_corner ) {
2022-08-07 12:36:04 +01:00
auto angle = [ & ] {
switch ( side_or_corner ) {
case SideOrCorner : : Top :
return 0.0f ;
case SideOrCorner : : Bottom :
return 180.0f ;
case SideOrCorner : : Left :
return 270.0f ;
case SideOrCorner : : Right :
return 90.0f ;
case SideOrCorner : : TopRight :
return corner_angle_degrees ( ) ;
case SideOrCorner : : BottomLeft :
return corner_angle_degrees ( ) + 180.0f ;
case SideOrCorner : : TopLeft :
return - corner_angle_degrees ( ) ;
case SideOrCorner : : BottomRight :
return - ( corner_angle_degrees ( ) + 180.0f ) ;
default :
VERIFY_NOT_REACHED ( ) ;
}
} ( ) ;
// Note: For unknowable reasons the angles are opposite on the -webkit- version
if ( m_gradient_type = = GradientType : : WebKit )
return angle + 180.0f ;
return angle ;
2022-07-12 00:09:29 +01:00
} ,
[ & ] ( Angle const & angle ) {
return angle . to_degrees ( ) ;
} ) ;
}
2022-12-06 21:44:49 +00:00
void LinearGradientStyleValue : : resolve_for_size ( Layout : : Node const & node , Gfx : : FloatSize size ) const
2022-07-31 01:11:59 +01:00
{
2022-08-22 21:46:09 +01:00
if ( m_resolved . has_value ( ) & & m_resolved - > size = = size )
return ;
2022-11-25 17:11:09 +00:00
m_resolved = ResolvedData { Painting : : resolve_linear_gradient_data ( node , size . to_type < CSSPixels > ( ) , * this ) , size } ;
2022-07-31 01:11:59 +01:00
}
2022-08-10 16:16:46 +01:00
void LinearGradientStyleValue : : paint ( PaintContext & context , Gfx : : IntRect const & dest_rect , CSS : : ImageRendering ) const
2022-07-31 01:11:59 +01:00
{
2022-08-22 21:46:09 +01:00
VERIFY ( m_resolved . has_value ( ) ) ;
2022-11-25 17:11:09 +00:00
Painting : : paint_linear_gradient ( context , dest_rect . to_type < DevicePixels > ( ) , m_resolved - > data ) ;
2022-07-31 01:11:59 +01:00
}
2022-10-29 13:11:00 +01:00
Gfx : : FloatPoint PositionValue : : resolved ( Layout : : Node const & node , Gfx : : FloatRect const & rect ) const
{
// Note: A preset + a none default x/y_relative_to is impossible in the syntax (and makes little sense)
float x = horizontal_position . visit (
[ & ] ( HorizontalPreset preset ) {
return rect . width ( ) * [ & ] {
switch ( preset ) {
case HorizontalPreset : : Left :
return 0.0f ;
case HorizontalPreset : : Center :
return 0.5f ;
case HorizontalPreset : : Right :
return 1.0f ;
default :
VERIFY_NOT_REACHED ( ) ;
}
} ( ) ;
} ,
[ & ] ( LengthPercentage length_percentage ) {
return length_percentage . resolved ( node , Length : : make_px ( rect . width ( ) ) ) . to_px ( node ) ;
} ) ;
float y = vertical_position . visit (
[ & ] ( VerticalPreset preset ) {
return rect . height ( ) * [ & ] {
switch ( preset ) {
case VerticalPreset : : Top :
return 0.0f ;
case VerticalPreset : : Center :
return 0.5f ;
case VerticalPreset : : Bottom :
return 1.0f ;
default :
VERIFY_NOT_REACHED ( ) ;
}
} ( ) ;
} ,
[ & ] ( LengthPercentage length_percentage ) {
return length_percentage . resolved ( node , Length : : make_px ( rect . height ( ) ) ) . to_px ( node ) ;
} ) ;
if ( x_relative_to = = HorizontalEdge : : Right )
x = rect . width ( ) - x ;
if ( y_relative_to = = VerticalEdge : : Bottom )
y = rect . height ( ) - y ;
return Gfx : : FloatPoint { rect . x ( ) + x , rect . y ( ) + y } ;
}
void PositionValue : : serialize ( StringBuilder & builder ) const
{
// Note: This means our serialization with simplify any with explicit edges that are just `top left`.
bool has_relative_edges = x_relative_to = = HorizontalEdge : : Right | | y_relative_to = = VerticalEdge : : Bottom ;
if ( has_relative_edges )
builder . append ( x_relative_to = = HorizontalEdge : : Left ? " left " sv : " right " sv ) ;
horizontal_position . visit (
[ & ] ( HorizontalPreset preset ) {
builder . append ( [ & ] {
switch ( preset ) {
case HorizontalPreset : : Left :
return " left " sv ;
case HorizontalPreset : : Center :
return " center " sv ;
case HorizontalPreset : : Right :
return " right " sv ;
default :
VERIFY_NOT_REACHED ( ) ;
}
} ( ) ) ;
} ,
[ & ] ( LengthPercentage length_percentage ) {
2022-12-06 01:12:49 +00:00
builder . append ( length_percentage . to_deprecated_string ( ) ) ;
2022-10-29 13:11:00 +01:00
} ) ;
builder . append ( ' ' ) ;
if ( has_relative_edges )
builder . append ( y_relative_to = = VerticalEdge : : Top ? " top " sv : " bottom " sv ) ;
vertical_position . visit (
[ & ] ( VerticalPreset preset ) {
builder . append ( [ & ] {
switch ( preset ) {
case VerticalPreset : : Top :
return " top " sv ;
case VerticalPreset : : Center :
return " center " sv ;
case VerticalPreset : : Bottom :
return " bottom " sv ;
default :
VERIFY_NOT_REACHED ( ) ;
}
} ( ) ) ;
} ,
[ & ] ( LengthPercentage length_percentage ) {
2022-12-06 01:12:49 +00:00
builder . append ( length_percentage . to_deprecated_string ( ) ) ;
2022-10-29 13:11:00 +01:00
} ) ;
}
bool PositionValue : : operator = = ( PositionValue const & other ) const
{
return (
x_relative_to = = other . x_relative_to
& & y_relative_to = = other . y_relative_to
& & variant_equals ( horizontal_position , other . horizontal_position )
& & variant_equals ( vertical_position , other . vertical_position ) ) ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString RadialGradientStyleValue : : to_deprecated_string ( ) const
2022-11-11 18:13:00 +01:00
{
StringBuilder builder ;
2022-12-02 19:20:25 +00:00
if ( is_repeating ( ) )
builder . append ( " repeating- " sv ) ;
2022-11-11 18:13:00 +01:00
builder . appendff ( " radial-gradient({} " sv ,
m_ending_shape = = EndingShape : : Circle ? " circle " sv : " ellipse " sv ) ;
m_size . visit (
[ & ] ( Extent extent ) {
builder . append ( [ & ] {
switch ( extent ) {
case Extent : : ClosestCorner :
return " closest-corner " sv ;
case Extent : : ClosestSide :
return " closest-side " sv ;
case Extent : : FarthestCorner :
return " farthest-corner " sv ;
case Extent : : FarthestSide :
return " farthest-side " sv ;
default :
VERIFY_NOT_REACHED ( ) ;
}
} ( ) ) ;
} ,
2022-12-06 01:12:49 +00:00
[ & ] ( CircleSize const & circle_size ) { builder . append ( circle_size . radius . to_deprecated_string ( ) ) ; } ,
[ & ] ( EllipseSize const & ellipse_size ) { builder . appendff ( " {} {} " , ellipse_size . radius_a . to_deprecated_string ( ) , ellipse_size . radius_b . to_deprecated_string ( ) ) ; } ) ;
2022-11-11 18:13:00 +01:00
if ( m_position ! = PositionValue : : center ( ) ) {
builder . appendff ( " at " sv ) ;
m_position . serialize ( builder ) ;
}
builder . append ( " , " sv ) ;
serialize_color_stop_list ( builder , m_color_stop_list ) ;
builder . append ( ' ) ' ) ;
2022-12-06 01:12:49 +00:00
return builder . to_deprecated_string ( ) ;
2022-11-11 18:13:00 +01:00
}
Gfx : : FloatSize RadialGradientStyleValue : : resolve_size ( Layout : : Node const & node , Gfx : : FloatPoint center , Gfx : : FloatRect const & size ) const
{
auto const side_shape = [ & ] ( auto distance_function ) {
auto const distance_from = [ & ] ( float v , float a , float b , auto distance_function ) {
return distance_function ( fabs ( a - v ) , fabs ( b - v ) ) ;
} ;
auto x_dist = distance_from ( center . x ( ) , size . left ( ) , size . right ( ) , distance_function ) ;
auto y_dist = distance_from ( center . y ( ) , size . top ( ) , size . bottom ( ) , distance_function ) ;
if ( m_ending_shape = = EndingShape : : Circle ) {
auto dist = distance_function ( x_dist , y_dist ) ;
return Gfx : : FloatSize { dist , dist } ;
} else {
return Gfx : : FloatSize { x_dist , y_dist } ;
}
} ;
auto const closest_side_shape = [ & ] {
return side_shape ( AK : : min < float > ) ;
} ;
auto const farthest_side_shape = [ & ] {
return side_shape ( AK : : max < float > ) ;
} ;
auto const corner_distance = [ & ] ( auto distance_compare , Gfx : : FloatPoint & corner ) {
auto top_left_distance = size . top_left ( ) . distance_from ( center ) ;
auto top_right_distance = size . top_right ( ) . distance_from ( center ) ;
auto bottom_right_distance = size . bottom_right ( ) . distance_from ( center ) ;
auto bottom_left_distance = size . bottom_left ( ) . distance_from ( center ) ;
auto distance = top_left_distance ;
if ( distance_compare ( top_right_distance , distance ) ) {
corner = size . top_right ( ) ;
distance = top_right_distance ;
}
if ( distance_compare ( bottom_right_distance , distance ) ) {
corner = size . top_right ( ) ;
distance = bottom_right_distance ;
}
if ( distance_compare ( bottom_left_distance , distance ) ) {
corner = size . top_right ( ) ;
distance = bottom_left_distance ;
}
return distance ;
} ;
auto const closest_corner_distance = [ & ] ( Gfx : : FloatPoint & corner ) {
return corner_distance ( [ ] ( float a , float b ) { return a < b ; } , corner ) ;
} ;
auto const farthest_corner_distance = [ & ] ( Gfx : : FloatPoint & corner ) {
return corner_distance ( [ ] ( float a , float b ) { return a > b ; } , corner ) ;
} ;
auto const corner_shape = [ & ] ( auto corner_distance , auto get_shape ) {
Gfx : : FloatPoint corner { } ;
auto distance = corner_distance ( corner ) ;
if ( m_ending_shape = = EndingShape : : Ellipse ) {
auto shape = get_shape ( ) ;
auto aspect_ratio = shape . width ( ) / shape . height ( ) ;
auto p = corner - center ;
auto radius_a = AK : : sqrt ( p . y ( ) * p . y ( ) * aspect_ratio * aspect_ratio + p . x ( ) * p . x ( ) ) ;
auto radius_b = radius_a / aspect_ratio ;
return Gfx : : FloatSize { radius_a , radius_b } ;
}
return Gfx : : FloatSize { distance , distance } ;
} ;
// https://w3c.github.io/csswg-drafts/css-images/#radial-gradient-syntax
2022-11-13 15:30:36 +00:00
auto resolved_size = m_size . visit (
2022-11-11 18:13:00 +01:00
[ & ] ( Extent extent ) {
switch ( extent ) {
case Extent : : ClosestSide :
// The ending shape is sized so that it exactly meets the side of the gradient box closest to the gradient’ s center.
// If the shape is an ellipse, it exactly meets the closest side in each dimension.
return closest_side_shape ( ) ;
case Extent : : ClosestCorner :
// The ending shape is sized so that it passes through the corner of the gradient box closest to the gradient’ s center.
// If the shape is an ellipse, the ending shape is given the same aspect-ratio it would have if closest-side were specified
return corner_shape ( closest_corner_distance , closest_side_shape ) ;
case Extent : : FarthestCorner :
// Same as closest-corner, except the ending shape is sized based on the farthest corner.
// If the shape is an ellipse, the ending shape is given the same aspect ratio it would have if farthest-side were specified.
return corner_shape ( farthest_corner_distance , farthest_side_shape ) ;
case Extent : : FarthestSide :
// Same as closest-side, except the ending shape is sized based on the farthest side(s).
return farthest_side_shape ( ) ;
default :
VERIFY_NOT_REACHED ( ) ;
}
} ,
[ & ] ( CircleSize const & circle_size ) {
auto radius = circle_size . radius . to_px ( node ) ;
return Gfx : : FloatSize { radius , radius } ;
} ,
[ & ] ( EllipseSize const & ellipse_size ) {
auto radius_a = ellipse_size . radius_a . resolved ( node , CSS : : Length : : make_px ( size . width ( ) ) ) . to_px ( node ) ;
auto radius_b = ellipse_size . radius_b . resolved ( node , CSS : : Length : : make_px ( size . height ( ) ) ) . to_px ( node ) ;
return Gfx : : FloatSize { radius_a , radius_b } ;
} ) ;
2022-11-13 15:30:36 +00:00
// Handle degenerate cases
// https://w3c.github.io/csswg-drafts/css-images/#degenerate-radials
constexpr auto arbitrary_small_number = 1e-10 ;
constexpr auto arbitrary_large_number = 1e10 ;
// If the ending shape is a circle with zero radius:
if ( m_ending_shape = = EndingShape : : Circle & & resolved_size . is_empty ( ) ) {
// Render as if the ending shape was a circle whose radius was an arbitrary very small number greater than zero.
// This will make the gradient continue to look like a circle.
return Gfx : : FloatSize { arbitrary_small_number , arbitrary_small_number } ;
}
// If the ending shape has zero width (regardless of the height):
if ( resolved_size . width ( ) < = 0 ) {
// Render as if the ending shape was an ellipse whose height was an arbitrary very large number
// and whose width was an arbitrary very small number greater than zero.
// This will make the gradient look similar to a horizontal linear gradient that is mirrored across the center of the ellipse.
// It also means that all color-stop positions specified with a percentage resolve to 0px.
return Gfx : : FloatSize { arbitrary_small_number , arbitrary_large_number } ;
}
// Otherwise, if the ending shape has zero height:
if ( resolved_size . height ( ) < = 0 ) {
// Render as if the ending shape was an ellipse whose width was an arbitrary very large number and whose height
// was an arbitrary very small number greater than zero. This will make the gradient look like a solid-color image equal
// to the color of the last color-stop, or equal to the average color of the gradient if it’ s repeating.
return Gfx : : FloatSize { arbitrary_large_number , arbitrary_small_number } ;
}
return resolved_size ;
2022-11-11 18:13:00 +01:00
}
2022-12-06 21:44:49 +00:00
void RadialGradientStyleValue : : resolve_for_size ( Layout : : Node const & node , Gfx : : FloatSize paint_size ) const
2022-11-11 18:13:00 +01:00
{
2022-11-13 00:33:42 +00:00
Gfx : : FloatRect gradient_box { { 0 , 0 } , paint_size } ;
auto center = m_position . resolved ( node , gradient_box ) ;
auto gradient_size = resolve_size ( node , center , gradient_box ) ;
if ( m_resolved . has_value ( ) & & m_resolved - > gradient_size = = gradient_size )
return ;
m_resolved = ResolvedData {
2022-11-25 17:11:09 +00:00
Painting : : resolve_radial_gradient_data ( node , gradient_size . to_type < CSSPixels > ( ) , * this ) ,
2022-11-13 00:33:42 +00:00
gradient_size ,
center ,
} ;
2022-11-11 18:13:00 +01:00
}
bool RadialGradientStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto & other_gradient = other . as_radial_gradient ( ) ;
return ( m_ending_shape = = other_gradient . m_ending_shape
& & variant_equals ( m_size , other_gradient . m_size )
& & m_position = = other_gradient . m_position
& & m_color_stop_list = = other_gradient . m_color_stop_list ) ;
}
2022-11-13 00:33:42 +00:00
void RadialGradientStyleValue : : paint ( PaintContext & context , Gfx : : IntRect const & dest_rect , CSS : : ImageRendering ) const
2022-11-11 18:13:00 +01:00
{
2022-11-13 00:33:42 +00:00
VERIFY ( m_resolved . has_value ( ) ) ;
2022-12-17 20:04:39 +00:00
Painting : : paint_radial_gradient ( context , dest_rect . to_type < DevicePixels > ( ) , m_resolved - > data ,
context . rounded_device_point ( m_resolved - > center . to_type < CSSPixels > ( ) ) ,
context . rounded_device_size ( m_resolved - > gradient_size . to_type < CSSPixels > ( ) ) ) ;
2022-11-11 18:13:00 +01:00
}
2022-12-06 01:12:49 +00:00
DeprecatedString ConicGradientStyleValue : : to_deprecated_string ( ) const
2022-10-28 20:44:00 +01:00
{
StringBuilder builder ;
2022-11-06 14:51:10 +00:00
if ( is_repeating ( ) )
builder . append ( " repeating- " sv ) ;
2022-10-28 20:44:00 +01:00
builder . append ( " conic-gradient( " sv ) ;
bool has_from_angle = false ;
bool has_at_position = false ;
if ( ( has_from_angle = m_from_angle . to_degrees ( ) ! = 0 ) )
2022-12-06 01:12:49 +00:00
builder . appendff ( " from {} " , m_from_angle . to_deprecated_string ( ) ) ;
2022-10-28 20:44:00 +01:00
if ( ( has_at_position = m_position ! = PositionValue : : center ( ) ) ) {
if ( has_from_angle )
builder . append ( ' ' ) ;
builder . appendff ( " at " sv ) ;
m_position . serialize ( builder ) ;
}
if ( has_from_angle | | has_at_position )
builder . append ( " , " sv ) ;
serialize_color_stop_list ( builder , m_color_stop_list ) ;
builder . append ( ' ) ' ) ;
2022-12-06 01:12:49 +00:00
return builder . to_deprecated_string ( ) ;
2022-10-28 20:44:00 +01:00
}
2022-12-06 21:44:49 +00:00
void ConicGradientStyleValue : : resolve_for_size ( Layout : : Node const & node , Gfx : : FloatSize size ) const
2022-10-28 20:44:00 +01:00
{
2022-10-30 19:28:00 +01:00
if ( ! m_resolved . has_value ( ) )
m_resolved = ResolvedData { Painting : : resolve_conic_gradient_data ( node , * this ) , { } } ;
m_resolved - > position = m_position . resolved ( node , Gfx : : FloatRect { { 0 , 0 } , size } ) ;
2022-10-28 20:44:00 +01:00
}
2022-10-30 19:28:00 +01:00
void ConicGradientStyleValue : : paint ( PaintContext & context , Gfx : : IntRect const & dest_rect , CSS : : ImageRendering ) const
2022-10-28 20:44:00 +01:00
{
2022-10-30 19:28:00 +01:00
VERIFY ( m_resolved . has_value ( ) ) ;
2022-11-25 17:11:09 +00:00
Painting : : paint_conic_gradient ( context , dest_rect . to_type < DevicePixels > ( ) , m_resolved - > data , context . rounded_device_point ( m_resolved - > position . to_type < CSSPixels > ( ) ) ) ;
2022-10-28 20:44:00 +01:00
}
2022-11-07 19:02:00 +01:00
bool ConicGradientStyleValue : : equals ( StyleValue const & other ) const
2022-10-28 20:44:00 +01:00
{
2022-11-07 19:02:00 +01:00
if ( type ( ) ! = other . type ( ) )
return false ;
auto & other_gradient = other . as_conic_gradient ( ) ;
return ( m_from_angle = = other_gradient . m_from_angle
& & m_position = = other_gradient . m_position
& & m_color_stop_list = = other_gradient . m_color_stop_list
& & m_repeating = = other_gradient . m_repeating ) ;
2022-10-28 20:44:00 +01:00
}
float ConicGradientStyleValue : : angle_degrees ( ) const
{
return m_from_angle . to_degrees ( ) ;
}
2022-04-18 17:42:03 +01:00
bool InheritStyleValue : : equals ( StyleValue const & other ) const
{
return type ( ) = = other . type ( ) ;
}
bool InitialStyleValue : : equals ( StyleValue const & other ) const
{
return type ( ) = = other . type ( ) ;
}
bool LengthStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
return m_length = = other . as_length ( ) . m_length ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString ListStyleStyleValue : : to_deprecated_string ( ) const
2022-02-02 20:39:04 +00:00
{
2022-12-06 01:12:49 +00:00
return DeprecatedString : : formatted ( " {} {} {} " , m_position - > to_deprecated_string ( ) , m_image - > to_deprecated_string ( ) , m_style_type - > to_deprecated_string ( ) ) ;
2022-02-02 20:39:04 +00:00
}
2022-04-18 17:42:03 +01:00
bool ListStyleStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_list_style ( ) ;
return m_position - > equals ( typed_other . m_position )
& & m_image - > equals ( typed_other . m_image )
& & m_style_type - > equals ( typed_other . m_style_type ) ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString NumericStyleValue : : to_deprecated_string ( ) const
2022-02-02 20:39:04 +00:00
{
return m_value . visit (
[ ] ( float value ) {
2022-12-04 18:02:33 +00:00
return DeprecatedString : : formatted ( " {} " , value ) ;
2022-02-02 20:39:04 +00:00
} ,
[ ] ( i64 value ) {
2022-12-04 18:02:33 +00:00
return DeprecatedString : : formatted ( " {} " , value ) ;
2022-02-02 20:39:04 +00:00
} ) ;
}
2022-04-18 17:42:03 +01:00
bool NumericStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
if ( has_integer ( ) ! = other . has_integer ( ) )
return false ;
if ( has_integer ( ) )
return m_value . get < i64 > ( ) = = other . as_numeric ( ) . m_value . get < i64 > ( ) ;
return m_value . get < float > ( ) = = other . as_numeric ( ) . m_value . get < float > ( ) ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString OverflowStyleValue : : to_deprecated_string ( ) const
2022-02-02 20:39:04 +00:00
{
2022-12-06 01:12:49 +00:00
return DeprecatedString : : formatted ( " {} {} " , m_overflow_x - > to_deprecated_string ( ) , m_overflow_y - > to_deprecated_string ( ) ) ;
2022-02-02 20:39:04 +00:00
}
2022-04-18 17:42:03 +01:00
bool OverflowStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_overflow ( ) ;
return m_overflow_x - > equals ( typed_other . m_overflow_x )
& & m_overflow_y - > equals ( typed_other . m_overflow_y ) ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString PercentageStyleValue : : to_deprecated_string ( ) const
2022-02-02 20:39:04 +00:00
{
2022-12-06 01:12:49 +00:00
return m_percentage . to_deprecated_string ( ) ;
2021-10-03 17:56:01 +02:00
}
2022-04-18 17:42:03 +01:00
bool PercentageStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
return m_percentage = = other . as_percentage ( ) . m_percentage ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString PositionStyleValue : : to_deprecated_string ( ) const
2021-10-31 16:02:29 +00:00
{
2022-12-06 01:12:49 +00:00
auto to_deprecated_string = [ ] ( PositionEdge edge ) {
2021-10-31 16:02:29 +00:00
switch ( edge ) {
case PositionEdge : : Left :
return " left " ;
case PositionEdge : : Right :
return " right " ;
case PositionEdge : : Top :
return " top " ;
case PositionEdge : : Bottom :
return " bottom " ;
}
VERIFY_NOT_REACHED ( ) ;
} ;
2022-12-06 01:12:49 +00:00
return DeprecatedString : : formatted ( " {} {} {} {} " , to_deprecated_string ( m_edge_x ) , m_offset_x . to_deprecated_string ( ) , to_deprecated_string ( m_edge_y ) , m_offset_y . to_deprecated_string ( ) ) ;
2021-10-31 16:02:29 +00:00
}
2022-04-18 17:42:03 +01:00
bool PositionStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_position ( ) ;
return m_edge_x = = typed_other . m_edge_x
& & m_offset_x = = typed_other . m_offset_x
& & m_edge_y = = typed_other . m_edge_y
& & m_offset_y = = typed_other . m_offset_y ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString RectStyleValue : : to_deprecated_string ( ) const
2022-07-31 18:46:35 +02:00
{
2022-12-04 18:02:33 +00:00
return DeprecatedString : : formatted ( " rect({} {} {} {}) " , m_rect . top_edge , m_rect . right_edge , m_rect . bottom_edge , m_rect . left_edge ) ;
2022-07-31 18:46:35 +02:00
}
bool RectStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_rect ( ) ;
return m_rect = = typed_other . rect ( ) ;
}
2022-04-18 17:42:03 +01:00
bool ResolutionStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
return m_resolution = = other . as_resolution ( ) . m_resolution ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString ShadowStyleValue : : to_deprecated_string ( ) const
2022-04-18 17:42:03 +01:00
{
StringBuilder builder ;
2022-12-06 01:12:49 +00:00
builder . appendff ( " {} {} {} {} {} " , m_color . to_deprecated_string ( ) , m_offset_x . to_deprecated_string ( ) , m_offset_y . to_deprecated_string ( ) , m_blur_radius . to_deprecated_string ( ) , m_spread_distance . to_deprecated_string ( ) ) ;
2022-04-18 17:42:03 +01:00
if ( m_placement = = ShadowPlacement : : Inner )
2022-07-11 17:32:29 +00:00
builder . append ( " inset " sv ) ;
2022-12-06 01:12:49 +00:00
return builder . to_deprecated_string ( ) ;
2022-04-18 17:42:03 +01:00
}
bool ShadowStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_shadow ( ) ;
return m_color = = typed_other . m_color
& & m_offset_x = = typed_other . m_offset_x
& & m_offset_y = = typed_other . m_offset_y
& & m_blur_radius = = typed_other . m_blur_radius
& & m_spread_distance = = typed_other . m_spread_distance
& & m_placement = = typed_other . m_placement ;
}
bool StringStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
return m_string = = other . as_string ( ) . m_string ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString TextDecorationStyleValue : : to_deprecated_string ( ) const
2022-02-02 20:39:04 +00:00
{
2022-12-06 01:12:49 +00:00
return DeprecatedString : : formatted ( " {} {} {} {} " , m_line - > to_deprecated_string ( ) , m_thickness - > to_deprecated_string ( ) , m_style - > to_deprecated_string ( ) , m_color - > to_deprecated_string ( ) ) ;
2022-02-02 20:39:04 +00:00
}
2022-04-18 17:42:03 +01:00
bool TextDecorationStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_text_decoration ( ) ;
return m_line - > equals ( typed_other . m_line )
& & m_thickness - > equals ( typed_other . m_thickness )
& & m_style - > equals ( typed_other . m_style )
& & m_color - > equals ( typed_other . m_color ) ;
}
bool TimeStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
return m_time = = other . as_time ( ) . m_time ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString TransformationStyleValue : : to_deprecated_string ( ) const
2022-02-02 20:39:04 +00:00
{
2022-02-02 21:19:43 +00:00
StringBuilder builder ;
2022-04-17 15:52:30 +01:00
builder . append ( CSS : : to_string ( m_transform_function ) ) ;
2022-02-02 21:19:43 +00:00
builder . append ( ' ( ' ) ;
2022-07-11 17:32:29 +00:00
builder . join ( " , " sv , m_values ) ;
2022-02-02 21:19:43 +00:00
builder . append ( ' ) ' ) ;
2022-12-06 01:12:49 +00:00
return builder . to_deprecated_string ( ) ;
2022-02-02 20:39:04 +00:00
}
2022-04-18 17:42:03 +01:00
bool TransformationStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_transformation ( ) ;
if ( m_transform_function ! = typed_other . m_transform_function )
return false ;
if ( m_values . size ( ) ! = typed_other . m_values . size ( ) )
return false ;
for ( size_t i = 0 ; i < m_values . size ( ) ; + + i ) {
if ( ! m_values [ i ] . equals ( typed_other . m_values [ i ] ) )
return false ;
}
return true ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString UnresolvedStyleValue : : to_deprecated_string ( ) const
2021-12-03 12:28:14 +00:00
{
StringBuilder builder ;
for ( auto & value : m_values )
2022-12-06 01:12:49 +00:00
builder . append ( value . to_deprecated_string ( ) ) ;
return builder . to_deprecated_string ( ) ;
2021-12-03 12:28:14 +00:00
}
2022-04-18 17:42:03 +01:00
bool UnresolvedStyleValue : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
// This is a case where comparing the strings actually makes sense.
2022-12-06 01:12:49 +00:00
return to_deprecated_string ( ) = = other . to_deprecated_string ( ) ;
2022-04-18 17:42:03 +01:00
}
bool UnsetStyleValue : : equals ( StyleValue const & other ) const
{
return type ( ) = = other . type ( ) ;
}
2022-12-06 01:12:49 +00:00
DeprecatedString StyleValueList : : to_deprecated_string ( ) const
2022-02-02 20:39:04 +00:00
{
2022-12-04 18:02:33 +00:00
DeprecatedString separator = " " ;
2022-02-02 20:53:55 +00:00
switch ( m_separator ) {
case Separator : : Space :
separator = " " ;
break ;
case Separator : : Comma :
separator = " , " ;
break ;
default :
VERIFY_NOT_REACHED ( ) ;
2022-02-02 20:39:04 +00:00
}
2022-02-02 20:53:55 +00:00
2022-12-04 18:02:33 +00:00
return DeprecatedString : : join ( separator , m_values ) ;
2022-02-02 20:39:04 +00:00
}
2022-04-18 17:42:03 +01:00
bool StyleValueList : : equals ( StyleValue const & other ) const
{
if ( type ( ) ! = other . type ( ) )
return false ;
auto const & typed_other = other . as_value_list ( ) ;
if ( m_separator ! = typed_other . m_separator )
return false ;
if ( m_values . size ( ) ! = typed_other . m_values . size ( ) )
return false ;
for ( size_t i = 0 ; i < m_values . size ( ) ; + + i ) {
if ( ! m_values [ i ] . equals ( typed_other . m_values [ i ] ) )
return false ;
}
return true ;
}
2022-02-18 20:26:09 +01:00
NonnullRefPtr < ColorStyleValue > ColorStyleValue : : create ( Color color )
{
if ( color . value ( ) = = 0 ) {
static auto transparent = adopt_ref ( * new ColorStyleValue ( color ) ) ;
return transparent ;
}
if ( color = = Color : : from_rgb ( 0x000000 ) ) {
static auto black = adopt_ref ( * new ColorStyleValue ( color ) ) ;
return black ;
}
if ( color = = Color : : from_rgb ( 0xffffff ) ) {
static auto white = adopt_ref ( * new ColorStyleValue ( color ) ) ;
return white ;
}
return adopt_ref ( * new ColorStyleValue ( color ) ) ;
}
2022-08-24 12:31:00 +02:00
NonnullRefPtr < GridTrackPlacementStyleValue > GridTrackPlacementStyleValue : : create ( CSS : : GridTrackPlacement grid_track_placement )
{
return adopt_ref ( * new GridTrackPlacementStyleValue ( grid_track_placement ) ) ;
}
2022-10-30 13:27:57 +01:00
NonnullRefPtr < GridTrackSizeStyleValue > GridTrackSizeStyleValue : : create ( CSS : : GridTrackSizeList grid_track_size_list )
2022-08-24 12:27:56 +02:00
{
2022-10-30 13:27:57 +01:00
return adopt_ref ( * new GridTrackSizeStyleValue ( grid_track_size_list ) ) ;
}
NonnullRefPtr < GridTrackSizeStyleValue > GridTrackSizeStyleValue : : make_auto ( )
{
return adopt_ref ( * new GridTrackSizeStyleValue ( CSS : : GridTrackSizeList ( ) ) ) ;
2022-08-24 12:27:56 +02:00
}
2022-07-31 18:46:35 +02:00
NonnullRefPtr < RectStyleValue > RectStyleValue : : create ( EdgeRect rect )
{
return adopt_ref ( * new RectStyleValue ( rect ) ) ;
}
2022-02-18 20:26:09 +01:00
NonnullRefPtr < LengthStyleValue > LengthStyleValue : : create ( Length const & length )
{
if ( length . is_auto ( ) ) {
static auto value = adopt_ref ( * new LengthStyleValue ( CSS : : Length : : make_auto ( ) ) ) ;
return value ;
}
if ( length . is_px ( ) ) {
if ( length . raw_value ( ) = = 0 ) {
static auto value = adopt_ref ( * new LengthStyleValue ( CSS : : Length : : make_px ( 0 ) ) ) ;
return value ;
}
if ( length . raw_value ( ) = = 1 ) {
static auto value = adopt_ref ( * new LengthStyleValue ( CSS : : Length : : make_px ( 1 ) ) ) ;
return value ;
}
}
return adopt_ref ( * new LengthStyleValue ( length ) ) ;
}
2022-03-28 12:03:44 +02:00
static Optional < CSS : : Length > absolutized_length ( CSS : : Length const & length , Gfx : : IntRect const & viewport_rect , Gfx : : FontPixelMetrics const & font_metrics , float font_size , float root_font_size )
2022-02-26 01:35:25 +01:00
{
if ( length . is_px ( ) )
return { } ;
if ( length . is_absolute ( ) | | length . is_relative ( ) ) {
auto px = length . to_px ( viewport_rect , font_metrics , font_size , root_font_size ) ;
return CSS : : Length : : make_px ( px ) ;
}
return { } ;
}
2022-03-28 12:03:44 +02:00
NonnullRefPtr < StyleValue > StyleValue : : absolutized ( Gfx : : IntRect const & , Gfx : : FontPixelMetrics const & , float , float ) const
2022-02-26 01:35:25 +01:00
{
return * this ;
}
2022-03-28 12:03:44 +02:00
NonnullRefPtr < StyleValue > LengthStyleValue : : absolutized ( Gfx : : IntRect const & viewport_rect , Gfx : : FontPixelMetrics const & font_metrics , float font_size , float root_font_size ) const
2022-02-26 01:35:25 +01:00
{
if ( auto length = absolutized_length ( m_length , viewport_rect , font_metrics , font_size , root_font_size ) ; length . has_value ( ) )
return LengthStyleValue : : create ( length . release_value ( ) ) ;
return * this ;
}
2022-03-28 12:03:44 +02:00
NonnullRefPtr < StyleValue > ShadowStyleValue : : absolutized ( Gfx : : IntRect const & viewport_rect , Gfx : : FontPixelMetrics const & font_metrics , float font_size , float root_font_size ) const
2022-02-26 01:35:25 +01:00
{
auto absolutized_offset_x = absolutized_length ( m_offset_x , viewport_rect , font_metrics , font_size , root_font_size ) . value_or ( m_offset_x ) ;
auto absolutized_offset_y = absolutized_length ( m_offset_y , viewport_rect , font_metrics , font_size , root_font_size ) . value_or ( m_offset_y ) ;
auto absolutized_blur_radius = absolutized_length ( m_blur_radius , viewport_rect , font_metrics , font_size , root_font_size ) . value_or ( m_blur_radius ) ;
auto absolutized_spread_distance = absolutized_length ( m_spread_distance , viewport_rect , font_metrics , font_size , root_font_size ) . value_or ( m_spread_distance ) ;
2022-03-23 16:55:22 +00:00
return ShadowStyleValue : : create ( m_color , absolutized_offset_x , absolutized_offset_y , absolutized_blur_radius , absolutized_spread_distance , m_placement ) ;
2022-02-26 01:35:25 +01:00
}
2022-03-28 12:03:44 +02:00
NonnullRefPtr < StyleValue > BorderRadiusStyleValue : : absolutized ( Gfx : : IntRect const & viewport_rect , Gfx : : FontPixelMetrics const & font_metrics , float font_size , float root_font_size ) const
2022-02-26 01:35:25 +01:00
{
if ( m_horizontal_radius . is_percentage ( ) & & m_vertical_radius . is_percentage ( ) )
return * this ;
auto absolutized_horizontal_radius = m_horizontal_radius ;
auto absolutized_vertical_radius = m_vertical_radius ;
if ( ! m_horizontal_radius . is_percentage ( ) )
absolutized_horizontal_radius = absolutized_length ( m_horizontal_radius . length ( ) , viewport_rect , font_metrics , font_size , root_font_size ) . value_or ( m_horizontal_radius . length ( ) ) ;
if ( ! m_vertical_radius . is_percentage ( ) )
absolutized_vertical_radius = absolutized_length ( m_vertical_radius . length ( ) , viewport_rect , font_metrics , font_size , root_font_size ) . value_or ( m_vertical_radius . length ( ) ) ;
return BorderRadiusStyleValue : : create ( absolutized_horizontal_radius , absolutized_vertical_radius ) ;
}
2022-09-14 11:28:15 +02:00
bool CalculatedStyleValue : : contains_percentage ( ) const
{
return m_expression - > contains_percentage ( ) ;
}
bool CalculatedStyleValue : : CalcSum : : contains_percentage ( ) const
{
if ( first_calc_product - > contains_percentage ( ) )
return true ;
for ( auto & part : zero_or_more_additional_calc_products ) {
if ( part . contains_percentage ( ) )
return true ;
}
return false ;
}
bool CalculatedStyleValue : : CalcSumPartWithOperator : : contains_percentage ( ) const
{
return value - > contains_percentage ( ) ;
}
bool CalculatedStyleValue : : CalcProduct : : contains_percentage ( ) const
{
if ( first_calc_value . contains_percentage ( ) )
return true ;
for ( auto & part : zero_or_more_additional_calc_values ) {
if ( part . contains_percentage ( ) )
return true ;
}
return false ;
}
bool CalculatedStyleValue : : CalcProductPartWithOperator : : contains_percentage ( ) const
{
return value . visit (
[ ] ( CalcValue const & value ) { return value . contains_percentage ( ) ; } ,
[ ] ( CalcNumberValue const & ) { return false ; } ) ;
}
bool CalculatedStyleValue : : CalcValue : : contains_percentage ( ) const
{
return value . visit (
[ ] ( Percentage const & ) { return true ; } ,
[ ] ( NonnullOwnPtr < CalcSum > const & sum ) { return sum - > contains_percentage ( ) ; } ,
[ ] ( auto const & ) { return false ; } ) ;
}
2022-09-27 18:12:54 +02:00
bool calculated_style_value_contains_percentage ( CalculatedStyleValue const & value )
{
return value . contains_percentage ( ) ;
}
2020-03-07 10:27:02 +01:00
}