2020-01-18 09:38:21 +01:00
/*
2025-02-26 18:16:36 +01:00
* Copyright ( c ) 2018 - 2025 , Andreas Kling < andreas @ ladybird . org >
2025-01-15 14:58:23 +00:00
* Copyright ( c ) 2021 - 2025 , Sam Atkins < sam @ ladybird . 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
*/
2024-11-03 13:20:04 +01:00
# include <AK/NonnullRawPtr.h>
2021-05-30 20:22:25 +02:00
# include <AK/TypeCasts.h>
2020-02-06 15:04:03 +01:00
# include <LibCore/DirIterator.h>
2024-12-20 16:35:12 +01:00
# include <LibGC/CellAllocator.h>
2022-07-31 18:47:09 +02:00
# include <LibWeb/CSS/Clip.h>
2024-12-20 11:32:17 +01:00
# include <LibWeb/CSS/ComputedProperties.h>
2023-03-23 17:26:13 +00:00
# include <LibWeb/CSS/StyleValues/AngleStyleValue.h>
2024-08-14 11:46:56 +01:00
# include <LibWeb/CSS/StyleValues/CSSKeywordValue.h>
2025-01-02 12:59:09 +11:00
# include <LibWeb/CSS/StyleValues/ColorSchemeStyleValue.h>
2023-03-23 21:17:43 +00:00
# include <LibWeb/CSS/StyleValues/ContentStyleValue.h>
2024-07-24 15:47:11 +01:00
# include <LibWeb/CSS/StyleValues/CounterDefinitionsStyleValue.h>
2024-07-18 20:29:02 +01:00
# include <LibWeb/CSS/StyleValues/CounterStyleValue.h>
2025-02-21 17:56:24 +01:00
# include <LibWeb/CSS/StyleValues/CustomIdentStyleValue.h>
2023-04-26 21:05:38 +02:00
# include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
2025-02-26 18:16:36 +01:00
# include <LibWeb/CSS/StyleValues/FitContentStyleValue.h>
2023-08-17 20:25:18 +02:00
# include <LibWeb/CSS/StyleValues/GridAutoFlowStyleValue.h>
2023-03-24 14:25:00 +00:00
# include <LibWeb/CSS/StyleValues/GridTemplateAreaStyleValue.h>
2023-03-24 14:53:08 +00:00
# include <LibWeb/CSS/StyleValues/GridTrackPlacementStyleValue.h>
2023-04-29 17:59:07 +02:00
# include <LibWeb/CSS/StyleValues/GridTrackSizeListStyleValue.h>
2023-06-01 17:01:09 +01:00
# include <LibWeb/CSS/StyleValues/IntegerStyleValue.h>
2023-05-27 12:28:25 +01:00
# include <LibWeb/CSS/StyleValues/LengthStyleValue.h>
2023-09-07 15:29:54 +01:00
# include <LibWeb/CSS/StyleValues/MathDepthStyleValue.h>
2023-06-01 16:16:15 +01:00
# include <LibWeb/CSS/StyleValues/NumberStyleValue.h>
2024-10-01 09:20:06 +01:00
# include <LibWeb/CSS/StyleValues/OpenTypeTaggedStyleValue.h>
2023-03-24 17:28:43 +00:00
# include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
2023-10-16 13:52:51 +02:00
# include <LibWeb/CSS/StyleValues/PositionStyleValue.h>
2023-03-25 00:02:50 +00:00
# include <LibWeb/CSS/StyleValues/RectStyleValue.h>
2024-06-26 23:19:38 +01:00
# include <LibWeb/CSS/StyleValues/ScrollbarGutterStyleValue.h>
2023-03-24 17:45:25 +00:00
# include <LibWeb/CSS/StyleValues/ShadowStyleValue.h>
2023-03-24 17:48:42 +00:00
# include <LibWeb/CSS/StyleValues/StringStyleValue.h>
2023-03-25 00:12:21 +00:00
# include <LibWeb/CSS/StyleValues/StyleValueList.h>
2023-03-24 17:59:33 +00:00
# include <LibWeb/CSS/StyleValues/TransformationStyleValue.h>
2021-10-06 20:02:41 +02:00
# include <LibWeb/Layout/BlockContainer.h>
2021-08-12 16:41:09 +01:00
# include <LibWeb/Layout/Node.h>
2022-09-17 21:25:50 +02:00
# include <LibWeb/Platform/FontPlugin.h>
2019-09-21 15:32:17 +03:00
2020-07-26 20:01:35 +02:00
namespace Web : : CSS {
2020-03-07 10:27:02 +01:00
2024-12-20 16:35:12 +01:00
GC_DEFINE_ALLOCATOR ( ComputedProperties ) ;
ComputedProperties : : ComputedProperties ( ) = default ;
ComputedProperties : : ~ ComputedProperties ( ) = default ;
void ComputedProperties : : visit_edges ( Visitor & visitor )
2024-08-02 13:59:19 +02:00
{
2024-12-20 16:35:12 +01:00
Base : : visit_edges ( visitor ) ;
visitor . visit ( m_animation_name_source ) ;
visitor . visit ( m_transition_property_source ) ;
2024-08-02 13:59:19 +02:00
}
2025-02-05 12:57:41 +00:00
bool ComputedProperties : : is_property_important ( PropertyID property_id ) const
2024-03-16 07:44:48 +01:00
{
2024-08-02 13:59:19 +02:00
size_t n = to_underlying ( property_id ) ;
2024-12-20 16:35:12 +01:00
return m_property_important [ n / 8 ] & ( 1 < < ( n % 8 ) ) ;
2024-08-02 13:59:19 +02:00
}
2025-02-05 12:57:41 +00:00
void ComputedProperties : : set_property_important ( PropertyID property_id , Important important )
2024-08-02 13:59:19 +02:00
{
size_t n = to_underlying ( property_id ) ;
if ( important = = Important : : Yes )
2024-12-20 16:35:12 +01:00
m_property_important [ n / 8 ] | = ( 1 < < ( n % 8 ) ) ;
2024-08-02 13:59:19 +02:00
else
2024-12-20 16:35:12 +01:00
m_property_important [ n / 8 ] & = ~ ( 1 < < ( n % 8 ) ) ;
2024-03-16 07:44:48 +01:00
}
2025-02-05 12:57:41 +00:00
bool ComputedProperties : : is_property_inherited ( PropertyID property_id ) const
2024-03-16 07:44:48 +01:00
{
2024-08-02 13:59:19 +02:00
size_t n = to_underlying ( property_id ) ;
2024-12-20 16:35:12 +01:00
return m_property_inherited [ n / 8 ] & ( 1 < < ( n % 8 ) ) ;
2024-08-02 13:59:19 +02:00
}
2025-02-05 12:57:41 +00:00
void ComputedProperties : : set_property_inherited ( PropertyID property_id , Inherited inherited )
2024-08-02 13:59:19 +02:00
{
size_t n = to_underlying ( property_id ) ;
if ( inherited = = Inherited : : Yes )
2024-12-20 16:35:12 +01:00
m_property_inherited [ n / 8 ] | = ( 1 < < ( n % 8 ) ) ;
2024-08-02 13:59:19 +02:00
else
2024-12-20 16:35:12 +01:00
m_property_inherited [ n / 8 ] & = ~ ( 1 < < ( n % 8 ) ) ;
2024-03-16 07:44:48 +01:00
}
2025-02-05 12:57:41 +00:00
void ComputedProperties : : set_property ( PropertyID id , NonnullRefPtr < CSSStyleValue const > value , Inherited inherited , Important important )
2024-03-16 07:44:48 +01:00
{
2024-12-20 16:35:12 +01:00
m_property_values [ to_underlying ( id ) ] = move ( value ) ;
2024-08-02 13:59:19 +02:00
set_property_important ( id , important ) ;
set_property_inherited ( id , inherited ) ;
2024-03-16 07:44:48 +01:00
}
2025-02-05 12:57:41 +00:00
void ComputedProperties : : revert_property ( PropertyID id , ComputedProperties const & style_for_revert )
2024-08-04 10:08:28 +02:00
{
2024-12-20 16:35:12 +01:00
m_property_values [ to_underlying ( id ) ] = style_for_revert . m_property_values [ to_underlying ( id ) ] ;
2024-08-04 10:08:28 +02:00
set_property_important ( id , style_for_revert . is_property_important ( id ) ? Important : : Yes : Important : : No ) ;
set_property_inherited ( id , style_for_revert . is_property_inherited ( id ) ? Inherited : : Yes : Inherited : : No ) ;
}
2025-02-05 12:57:41 +00:00
void ComputedProperties : : set_animated_property ( PropertyID id , NonnullRefPtr < CSSStyleValue const > value )
2024-03-16 07:44:48 +01:00
{
2024-12-20 16:35:12 +01:00
m_animated_property_values . set ( id , move ( value ) ) ;
2024-03-16 07:44:48 +01:00
}
2024-12-20 11:32:17 +01:00
void ComputedProperties : : reset_animated_properties ( )
2024-03-16 07:44:48 +01:00
{
2024-12-20 16:35:12 +01:00
m_animated_property_values . clear ( ) ;
2019-09-21 15:32:17 +03:00
}
2025-02-05 12:57:41 +00:00
CSSStyleValue const & ComputedProperties : : property ( PropertyID property_id , WithAnimationsApplied return_animated_value ) const
2019-09-21 15:32:17 +03:00
{
2024-09-19 10:46:32 +01:00
if ( return_animated_value = = WithAnimationsApplied : : Yes ) {
2024-12-20 16:35:12 +01:00
if ( auto animated_value = m_animated_property_values . get ( property_id ) ; animated_value . has_value ( ) )
2024-11-03 13:20:04 +01:00
return * animated_value . value ( ) ;
2024-09-19 10:46:32 +01:00
}
2024-03-16 07:44:48 +01:00
2022-04-14 11:52:35 +01:00
// By the time we call this method, all properties have values assigned.
2024-12-20 16:35:12 +01:00
return * m_property_values [ to_underlying ( property_id ) ] ;
2019-09-21 15:32:17 +03:00
}
2025-02-05 12:57:41 +00:00
CSSStyleValue const * ComputedProperties : : maybe_null_property ( PropertyID property_id ) const
2022-10-28 15:42:18 +01:00
{
2024-12-20 16:35:12 +01:00
if ( auto animated_value = m_animated_property_values . get ( property_id ) ; animated_value . has_value ( ) )
2024-11-03 13:20:04 +01:00
return animated_value . value ( ) ;
2024-12-20 16:35:12 +01:00
return m_property_values [ to_underlying ( property_id ) ] ;
2023-05-26 23:25:25 +03:30
}
2025-02-05 12:57:41 +00:00
Variant < LengthPercentage , NormalGap > ComputedProperties : : gap_value ( PropertyID id ) const
2024-11-09 17:38:09 +01:00
{
auto const & value = property ( id ) ;
if ( value . is_keyword ( ) ) {
2025-02-05 12:57:41 +00:00
VERIFY ( value . as_keyword ( ) . keyword ( ) = = Keyword : : Normal ) ;
2024-11-09 17:38:09 +01:00
return NormalGap { } ;
}
2024-12-11 15:05:56 +00:00
if ( value . is_calculated ( ) )
2024-12-11 15:16:34 +00:00
return LengthPercentage { value . as_calculated ( ) } ;
2024-11-09 17:38:09 +01:00
if ( value . is_percentage ( ) )
return LengthPercentage { value . as_percentage ( ) . percentage ( ) } ;
if ( value . is_length ( ) )
return LengthPercentage { value . as_length ( ) . length ( ) } ;
VERIFY_NOT_REACHED ( ) ;
}
2025-02-05 12:57:41 +00:00
Size ComputedProperties : : size_value ( PropertyID id ) const
2022-09-25 15:47:40 +02:00
{
2024-11-03 13:20:04 +01:00
auto const & value = property ( id ) ;
if ( value . is_keyword ( ) ) {
switch ( value . to_keyword ( ) ) {
2024-08-14 14:06:03 +01:00
case Keyword : : Auto :
2025-02-05 12:57:41 +00:00
return Size : : make_auto ( ) ;
2024-08-14 14:06:03 +01:00
case Keyword : : MinContent :
2025-02-05 12:57:41 +00:00
return Size : : make_min_content ( ) ;
2024-08-14 14:06:03 +01:00
case Keyword : : MaxContent :
2025-02-05 12:57:41 +00:00
return Size : : make_max_content ( ) ;
2024-08-14 14:06:03 +01:00
case Keyword : : None :
2025-02-05 12:57:41 +00:00
return Size : : make_none ( ) ;
2022-09-25 15:47:40 +02:00
default :
VERIFY_NOT_REACHED ( ) ;
}
}
2025-02-26 18:16:36 +01:00
if ( value . is_fit_content ( ) ) {
auto & fit_content = value . as_fit_content ( ) ;
return Size : : make_fit_content ( fit_content . length_percentage ( ) ) ;
}
2022-09-25 15:47:40 +02:00
2024-12-11 15:05:56 +00:00
if ( value . is_calculated ( ) )
2025-02-05 12:57:41 +00:00
return Size : : make_calculated ( value . as_calculated ( ) ) ;
2022-09-25 15:47:40 +02:00
2024-11-03 13:20:04 +01:00
if ( value . is_percentage ( ) )
2025-02-05 12:57:41 +00:00
return Size : : make_percentage ( value . as_percentage ( ) . percentage ( ) ) ;
2022-09-25 15:47:40 +02:00
2024-11-03 13:20:04 +01:00
if ( value . is_length ( ) ) {
auto length = value . as_length ( ) . length ( ) ;
2022-09-25 15:47:40 +02:00
if ( length . is_auto ( ) )
2025-02-05 12:57:41 +00:00
return Size : : make_auto ( ) ;
return Size : : make_length ( length ) ;
2022-09-25 15:47:40 +02:00
}
// FIXME: Support `fit-content(<length>)`
2024-12-07 00:59:49 +01:00
dbgln ( " FIXME: Unsupported size value: `{}`, treating as `auto` " , value . to_string ( CSSStyleValue : : SerializationMode : : Normal ) ) ;
2025-02-05 12:57:41 +00:00
return Size : : make_auto ( ) ;
2022-09-25 15:47:40 +02:00
}
2025-02-05 12:57:41 +00:00
LengthPercentage ComputedProperties : : length_percentage_or_fallback ( PropertyID id , LengthPercentage const & fallback ) const
2022-02-18 15:10:11 +00:00
{
return length_percentage ( id ) . value_or ( fallback ) ;
}
2025-02-05 12:57:41 +00:00
Optional < LengthPercentage > ComputedProperties : : length_percentage ( PropertyID id ) const
2022-01-19 16:19:43 +00:00
{
2024-11-03 13:20:04 +01:00
auto const & value = property ( id ) ;
2022-01-19 16:19:43 +00:00
2024-12-11 15:05:56 +00:00
if ( value . is_calculated ( ) )
2024-12-11 15:16:34 +00:00
return LengthPercentage { value . as_calculated ( ) } ;
2022-01-19 16:19:43 +00:00
2024-11-03 13:20:04 +01:00
if ( value . is_percentage ( ) )
return value . as_percentage ( ) . percentage ( ) ;
2022-01-19 16:19:43 +00:00
2024-11-03 13:20:04 +01:00
if ( value . is_length ( ) )
return value . as_length ( ) . length ( ) ;
2022-01-19 16:19:43 +00:00
2024-11-03 13:20:04 +01:00
if ( value . has_auto ( ) )
2023-04-19 11:26:49 +01:00
return LengthPercentage { Length : : make_auto ( ) } ;
2022-02-18 15:10:11 +00:00
return { } ;
2019-09-21 15:32:17 +03:00
}
2019-09-25 11:55:04 +03:00
2025-02-05 12:57:41 +00:00
LengthBox ComputedProperties : : length_box ( PropertyID left_id , PropertyID top_id , PropertyID right_id , PropertyID bottom_id , Length const & default_value ) const
2020-05-11 23:04:59 +02:00
{
2020-06-24 17:45:42 +02:00
LengthBox box ;
2022-09-13 17:42:39 +02:00
box . left ( ) = length_percentage_or_fallback ( left_id , default_value ) ;
box . top ( ) = length_percentage_or_fallback ( top_id , default_value ) ;
box . right ( ) = length_percentage_or_fallback ( right_id , default_value ) ;
box . bottom ( ) = length_percentage_or_fallback ( bottom_id , default_value ) ;
2020-06-24 17:45:42 +02:00
return box ;
2020-05-11 23:04:59 +02:00
}
2025-02-05 12:57:41 +00:00
Color ComputedProperties : : color_or_fallback ( PropertyID id , Layout : : NodeWithStyle const & node , Color fallback ) const
2019-09-28 22:18:19 +02:00
{
2024-11-03 13:20:04 +01:00
auto const & value = property ( id ) ;
if ( ! value . has_color ( ) )
2019-09-28 22:18:19 +02:00
return fallback ;
2024-11-03 13:20:04 +01:00
return value . to_color ( node ) ;
2019-09-28 22:18:19 +02:00
}
2019-10-06 11:23:58 +02:00
2025-01-02 12:59:09 +11:00
// https://drafts.csswg.org/css-color-adjust-1/#determine-the-used-color-scheme
2025-02-05 12:57:41 +00:00
PreferredColorScheme ComputedProperties : : color_scheme ( PreferredColorScheme preferred_scheme , Optional < Vector < String > const & > document_supported_schemes ) const
2025-01-02 12:59:09 +11:00
{
// To determine the used color scheme of an element:
2025-02-05 12:57:41 +00:00
auto const & scheme_value = property ( PropertyID : : ColorScheme ) . as_color_scheme ( ) ;
2025-01-02 12:59:09 +11:00
// 1. If the user’ s preferred color scheme, as indicated by the prefers-color-scheme media feature,
// is present among the listed color schemes, and is supported by the user agent,
// that’ s the element’ s used color scheme.
2025-02-05 12:57:41 +00:00
if ( preferred_scheme ! = PreferredColorScheme : : Auto & & scheme_value . schemes ( ) . contains_slow ( preferred_color_scheme_to_string ( preferred_scheme ) ) )
2025-01-02 12:59:09 +11:00
return preferred_scheme ;
// 2. Otherwise, if the user has indicated an overriding preference for their chosen color scheme,
// and the only keyword is not present in color-scheme for the element,
// the user agent must override the color scheme with the user’ s preferred color scheme.
// See § 2.3 Overriding the Color Scheme.
// FIXME: We don't currently support setting an "overriding preference" for color schemes.
// 3. Otherwise, if the user agent supports at least one of the listed color schemes,
// the used color scheme is the first supported color scheme in the list.
2025-02-05 12:57:41 +00:00
auto first_supported = scheme_value . schemes ( ) . first_matching ( [ ] ( auto scheme ) { return preferred_color_scheme_from_string ( scheme ) ! = PreferredColorScheme : : Auto ; } ) ;
2025-01-02 12:59:09 +11:00
if ( first_supported . has_value ( ) )
return preferred_color_scheme_from_string ( first_supported . value ( ) ) ;
// 4. Otherwise, the used color scheme is the browser default. (Same as normal.)
2025-01-04 09:59:57 +11:00
// `normal` indicates that the element supports the page’ s supported color schemes, if they are set
if ( document_supported_schemes . has_value ( ) ) {
2025-02-05 12:57:41 +00:00
if ( preferred_scheme ! = PreferredColorScheme : : Auto & & document_supported_schemes - > contains_slow ( preferred_color_scheme_to_string ( preferred_scheme ) ) )
2025-01-04 09:59:57 +11:00
return preferred_scheme ;
2025-02-05 12:57:41 +00:00
auto document_first_supported = document_supported_schemes - > first_matching ( [ ] ( auto scheme ) { return preferred_color_scheme_from_string ( scheme ) ! = PreferredColorScheme : : Auto ; } ) ;
2025-01-04 09:59:57 +11:00
if ( document_first_supported . has_value ( ) )
return preferred_color_scheme_from_string ( document_first_supported . value ( ) ) ;
}
2025-02-05 12:57:41 +00:00
return PreferredColorScheme : : Light ;
2025-01-02 12:59:09 +11:00
}
2025-01-02 03:56:05 +03:00
NonnullRefPtr < Gfx : : Font const > ComputedProperties : : font_fallback ( bool monospace , bool bold , float point_size )
2021-04-22 20:47:47 +02:00
{
if ( monospace & & bold )
2022-09-17 21:25:50 +02:00
return Platform : : FontPlugin : : the ( ) . default_fixed_width_font ( ) . bold_variant ( ) ;
2021-04-22 20:47:47 +02:00
if ( monospace )
2022-09-17 21:25:50 +02:00
return Platform : : FontPlugin : : the ( ) . default_fixed_width_font ( ) ;
2021-04-22 20:47:47 +02:00
if ( bold )
2025-01-02 03:56:05 +03:00
return Platform : : FontPlugin : : the ( ) . default_font ( point_size ) - > bold_variant ( ) ;
2021-04-22 20:47:47 +02:00
2025-01-02 03:56:05 +03:00
return * Platform : : FontPlugin : : the ( ) . default_font ( point_size ) ;
2021-04-22 20:47:47 +02:00
}
2024-12-20 11:32:17 +01:00
CSSPixels ComputedProperties : : compute_line_height ( CSSPixelRect const & viewport_rect , Length : : FontMetrics const & font_metrics , Length : : FontMetrics const & root_font_metrics ) const
2023-03-17 23:08:45 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & line_height = property ( PropertyID : : LineHeight ) ;
2023-03-17 23:08:45 +01:00
2024-11-03 13:20:04 +01:00
if ( line_height . is_keyword ( ) & & line_height . to_keyword ( ) = = Keyword : : Normal )
2023-04-28 16:29:12 +01:00
return font_metrics . line_height ;
2023-03-17 23:08:45 +01:00
2024-11-03 13:20:04 +01:00
if ( line_height . is_length ( ) ) {
auto line_height_length = line_height . as_length ( ) . length ( ) ;
2023-03-17 23:08:45 +01:00
if ( ! line_height_length . is_auto ( ) )
2023-04-28 16:29:12 +01:00
return line_height_length . to_px ( viewport_rect , font_metrics , root_font_metrics ) ;
2023-03-17 23:08:45 +01:00
}
2024-11-03 13:20:04 +01:00
if ( line_height . is_number ( ) )
return Length ( line_height . as_number ( ) . number ( ) , Length : : Type : : Em ) . to_px ( viewport_rect , font_metrics , root_font_metrics ) ;
2023-03-17 23:08:45 +01:00
2024-11-03 13:20:04 +01:00
if ( line_height . is_percentage ( ) ) {
2023-03-17 23:08:45 +01:00
// Percentages are relative to 1em. https://www.w3.org/TR/css-inline-3/#valdef-line-height-percentage
2024-11-03 13:20:04 +01:00
auto const & percentage = line_height . as_percentage ( ) . percentage ( ) ;
2023-04-28 16:29:12 +01:00
return Length ( percentage . as_fraction ( ) , Length : : Type : : Em ) . to_px ( viewport_rect , font_metrics , root_font_metrics ) ;
2023-03-17 23:08:45 +01:00
}
2024-12-11 15:05:56 +00:00
if ( line_height . is_calculated ( ) ) {
LibWeb/CSS: Wrap calc()-resolution data in a struct
Initially I added this to the existing CalculationContext, but in
reality, we have some data at parse-time and different data at
resolve-time, so it made more sense to keep those separate.
Instead of needing a variety of methods for resolving a Foo, depending
on whether we have a Layout::Node available, or a percentage basis, or
a length resolution context... put those in a
CalculationResolutionContext, and just pass that one thing to these
methods. This also removes the need for separate resolve_*_percentage()
methods, because we can just pass the percentage basis in to the regular
resolve_foo() method.
This also corrects the issue that *any* calculation may need to resolve
lengths, but we previously only passed a length resolution context to
specific types in some situations. Now, they can all have one available,
though it's up to the caller to provide it.
2025-01-22 16:05:32 +00:00
CalculationResolutionContext context {
. percentage_basis = Length ( 1 , Length : : Type : : Em ) ,
. length_resolution_context = Length : : ResolutionContext { viewport_rect , font_metrics , root_font_metrics } ,
} ;
2024-12-11 15:05:56 +00:00
if ( line_height . as_calculated ( ) . resolves_to_number ( ) ) {
LibWeb/CSS: Wrap calc()-resolution data in a struct
Initially I added this to the existing CalculationContext, but in
reality, we have some data at parse-time and different data at
resolve-time, so it made more sense to keep those separate.
Instead of needing a variety of methods for resolving a Foo, depending
on whether we have a Layout::Node available, or a percentage basis, or
a length resolution context... put those in a
CalculationResolutionContext, and just pass that one thing to these
methods. This also removes the need for separate resolve_*_percentage()
methods, because we can just pass the percentage basis in to the regular
resolve_foo() method.
This also corrects the issue that *any* calculation may need to resolve
lengths, but we previously only passed a length resolution context to
specific types in some situations. Now, they can all have one available,
though it's up to the caller to provide it.
2025-01-22 16:05:32 +00:00
auto resolved = line_height . as_calculated ( ) . resolve_number ( context ) ;
2024-01-12 12:39:40 +01:00
if ( ! resolved . has_value ( ) ) {
2024-12-11 15:05:56 +00:00
dbgln ( " FIXME: Failed to resolve calc() line-height (number): {} " , line_height . as_calculated ( ) . to_string ( CSSStyleValue : : SerializationMode : : Normal ) ) ;
2024-12-20 16:35:12 +01:00
return CSSPixels : : nearest_value_for ( m_font_list - > first ( ) . pixel_metrics ( ) . line_spacing ( ) ) ;
2024-01-12 12:39:40 +01:00
}
return Length ( resolved . value ( ) , Length : : Type : : Em ) . to_px ( viewport_rect , font_metrics , root_font_metrics ) ;
}
LibWeb/CSS: Wrap calc()-resolution data in a struct
Initially I added this to the existing CalculationContext, but in
reality, we have some data at parse-time and different data at
resolve-time, so it made more sense to keep those separate.
Instead of needing a variety of methods for resolving a Foo, depending
on whether we have a Layout::Node available, or a percentage basis, or
a length resolution context... put those in a
CalculationResolutionContext, and just pass that one thing to these
methods. This also removes the need for separate resolve_*_percentage()
methods, because we can just pass the percentage basis in to the regular
resolve_foo() method.
This also corrects the issue that *any* calculation may need to resolve
lengths, but we previously only passed a length resolution context to
specific types in some situations. Now, they can all have one available,
though it's up to the caller to provide it.
2025-01-22 16:05:32 +00:00
auto resolved = line_height . as_calculated ( ) . resolve_length ( context ) ;
2024-01-12 12:39:40 +01:00
if ( ! resolved . has_value ( ) ) {
2024-12-11 15:05:56 +00:00
dbgln ( " FIXME: Failed to resolve calc() line-height: {} " , line_height . as_calculated ( ) . to_string ( CSSStyleValue : : SerializationMode : : Normal ) ) ;
2024-12-20 16:35:12 +01:00
return CSSPixels : : nearest_value_for ( m_font_list - > first ( ) . pixel_metrics ( ) . line_spacing ( ) ) ;
2024-01-12 12:39:40 +01:00
}
return resolved - > to_px ( viewport_rect , font_metrics , root_font_metrics ) ;
2023-03-18 21:15:51 +01:00
}
2023-03-17 23:08:45 +01:00
2023-04-28 16:29:12 +01:00
return font_metrics . line_height ;
2023-03-17 23:08:45 +01:00
}
2024-12-20 11:32:17 +01:00
Optional < int > ComputedProperties : : z_index ( ) const
2020-06-15 17:29:35 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : ZIndex ) ;
2024-11-03 13:20:04 +01:00
if ( value . has_auto ( ) )
2022-03-04 15:01:01 +01:00
return { } ;
2024-11-03 13:20:04 +01:00
if ( value . is_integer ( ) ) {
2023-04-26 07:19:07 +02:00
// Clamp z-index to the range of a signed 32-bit integer for consistency with other engines.
2024-11-03 13:20:04 +01:00
auto integer = value . as_integer ( ) . integer ( ) ;
2023-06-01 17:01:09 +01:00
if ( integer > = NumericLimits < int > : : max ( ) )
2023-04-26 07:19:07 +02:00
return NumericLimits < int > : : max ( ) ;
2023-06-01 17:01:09 +01:00
if ( integer < = NumericLimits < int > : : min ( ) )
2023-04-26 07:19:07 +02:00
return NumericLimits < int > : : min ( ) ;
return static_cast < int > ( integer ) ;
}
2021-09-10 20:37:09 +01:00
return { } ;
2020-06-15 17:29:35 +02:00
}
2024-12-20 11:32:17 +01:00
float ComputedProperties : : resolve_opacity_value ( CSSStyleValue const & value )
2021-07-23 13:18:09 +03:00
{
2022-01-27 17:44:22 +00:00
float unclamped_opacity = 1.0f ;
2023-06-01 16:16:15 +01:00
if ( value . is_number ( ) ) {
unclamped_opacity = value . as_number ( ) . number ( ) ;
2024-12-11 15:05:56 +00:00
} else if ( value . is_calculated ( ) ) {
auto const & calculated = value . as_calculated ( ) ;
LibWeb/CSS: Wrap calc()-resolution data in a struct
Initially I added this to the existing CalculationContext, but in
reality, we have some data at parse-time and different data at
resolve-time, so it made more sense to keep those separate.
Instead of needing a variety of methods for resolving a Foo, depending
on whether we have a Layout::Node available, or a percentage basis, or
a length resolution context... put those in a
CalculationResolutionContext, and just pass that one thing to these
methods. This also removes the need for separate resolve_*_percentage()
methods, because we can just pass the percentage basis in to the regular
resolve_foo() method.
This also corrects the issue that *any* calculation may need to resolve
lengths, but we previously only passed a length resolution context to
specific types in some situations. Now, they can all have one available,
though it's up to the caller to provide it.
2025-01-22 16:05:32 +00:00
CalculationResolutionContext context { } ;
2023-06-30 16:29:06 +01:00
if ( calculated . resolves_to_percentage ( ) ) {
LibWeb/CSS: Wrap calc()-resolution data in a struct
Initially I added this to the existing CalculationContext, but in
reality, we have some data at parse-time and different data at
resolve-time, so it made more sense to keep those separate.
Instead of needing a variety of methods for resolving a Foo, depending
on whether we have a Layout::Node available, or a percentage basis, or
a length resolution context... put those in a
CalculationResolutionContext, and just pass that one thing to these
methods. This also removes the need for separate resolve_*_percentage()
methods, because we can just pass the percentage basis in to the regular
resolve_foo() method.
This also corrects the issue that *any* calculation may need to resolve
lengths, but we previously only passed a length resolution context to
specific types in some situations. Now, they can all have one available,
though it's up to the caller to provide it.
2025-01-22 16:05:32 +00:00
auto maybe_percentage = value . as_calculated ( ) . resolve_percentage ( context ) ;
2022-01-27 17:44:22 +00:00
if ( maybe_percentage . has_value ( ) )
unclamped_opacity = maybe_percentage - > as_fraction ( ) ;
else
2024-12-07 00:59:49 +01:00
dbgln ( " Unable to resolve calc() as opacity (percentage): {} " , value . to_string ( CSSStyleValue : : SerializationMode : : Normal ) ) ;
2023-06-30 16:29:06 +01:00
} else if ( calculated . resolves_to_number ( ) ) {
LibWeb/CSS: Wrap calc()-resolution data in a struct
Initially I added this to the existing CalculationContext, but in
reality, we have some data at parse-time and different data at
resolve-time, so it made more sense to keep those separate.
Instead of needing a variety of methods for resolving a Foo, depending
on whether we have a Layout::Node available, or a percentage basis, or
a length resolution context... put those in a
CalculationResolutionContext, and just pass that one thing to these
methods. This also removes the need for separate resolve_*_percentage()
methods, because we can just pass the percentage basis in to the regular
resolve_foo() method.
This also corrects the issue that *any* calculation may need to resolve
lengths, but we previously only passed a length resolution context to
specific types in some situations. Now, they can all have one available,
though it's up to the caller to provide it.
2025-01-22 16:05:32 +00:00
auto maybe_number = value . as_calculated ( ) . resolve_number ( context ) ;
2022-01-27 17:44:22 +00:00
if ( maybe_number . has_value ( ) )
unclamped_opacity = maybe_number . value ( ) ;
else
2024-12-07 00:59:49 +01:00
dbgln ( " Unable to resolve calc() as opacity (number): {} " , value . to_string ( CSSStyleValue : : SerializationMode : : Normal ) ) ;
2022-01-27 17:44:22 +00:00
}
2023-05-19 20:35:39 +01:00
} else if ( value . is_percentage ( ) ) {
unclamped_opacity = value . as_percentage ( ) . percentage ( ) . as_fraction ( ) ;
2022-01-27 17:44:22 +00:00
}
2021-07-23 13:18:09 +03:00
2022-01-27 17:44:22 +00:00
return clamp ( unclamped_opacity , 0.0f , 1.0f ) ;
2021-07-23 13:18:09 +03:00
}
2024-12-20 11:32:17 +01:00
float ComputedProperties : : opacity ( ) const
2023-05-19 20:35:39 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : Opacity ) ;
2024-11-03 13:20:04 +01:00
return resolve_opacity_value ( value ) ;
2023-05-19 20:35:39 +01:00
}
2024-12-20 11:32:17 +01:00
float ComputedProperties : : fill_opacity ( ) const
2023-05-19 20:35:39 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : FillOpacity ) ;
2024-11-03 13:20:04 +01:00
return resolve_opacity_value ( value ) ;
2023-05-19 20:35:39 +01:00
}
2025-02-05 12:55:02 +00:00
StrokeLinecap ComputedProperties : : stroke_linecap ( ) const
2024-10-10 10:15:49 -04:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : StrokeLinecap ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_stroke_linecap ( value . to_keyword ( ) ) . release_value ( ) ;
2024-10-10 10:15:49 -04:00
}
2025-02-05 12:55:02 +00:00
StrokeLinejoin ComputedProperties : : stroke_linejoin ( ) const
2024-10-28 20:51:16 -04:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : StrokeLinejoin ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_stroke_linejoin ( value . to_keyword ( ) ) . release_value ( ) ;
2024-10-28 20:51:16 -04:00
}
2024-12-20 11:32:17 +01:00
NumberOrCalculated ComputedProperties : : stroke_miterlimit ( ) const
2024-10-28 20:51:16 -04:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : StrokeMiterlimit ) ;
2024-10-28 20:51:16 -04:00
2024-12-11 15:05:56 +00:00
if ( value . is_calculated ( ) ) {
auto const & math_value = value . as_calculated ( ) ;
2024-10-28 20:51:16 -04:00
VERIFY ( math_value . resolves_to_number ( ) ) ;
return NumberOrCalculated { math_value } ;
}
2024-11-03 13:20:04 +01:00
return NumberOrCalculated { value . as_number ( ) . number ( ) } ;
2024-10-28 20:51:16 -04:00
}
2024-12-20 11:32:17 +01:00
float ComputedProperties : : stroke_opacity ( ) const
2023-05-19 20:35:39 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : StrokeOpacity ) ;
2024-11-03 13:20:04 +01:00
return resolve_opacity_value ( value ) ;
2023-05-19 20:35:39 +01:00
}
2024-12-20 11:32:17 +01:00
float ComputedProperties : : stop_opacity ( ) const
2023-05-19 20:35:39 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : StopOpacity ) ;
2024-11-03 13:20:04 +01:00
return resolve_opacity_value ( value ) ;
2023-05-19 20:35:39 +01:00
}
2025-02-05 12:55:02 +00:00
FillRule ComputedProperties : : fill_rule ( ) const
2023-06-11 16:43:46 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : FillRule ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_fill_rule ( value . to_keyword ( ) ) . release_value ( ) ;
2023-06-11 16:43:46 +01:00
}
2025-02-05 12:55:02 +00:00
ClipRule ComputedProperties : : clip_rule ( ) const
2024-05-12 20:19:43 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : ClipRule ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_fill_rule ( value . to_keyword ( ) ) . release_value ( ) ;
2024-05-12 20:19:43 +01:00
}
2025-02-05 12:55:02 +00:00
FlexDirection ComputedProperties : : flex_direction ( ) const
2021-01-18 17:41:57 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : FlexDirection ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_flex_direction ( value . to_keyword ( ) ) . release_value ( ) ;
2021-01-18 17:41:57 +01:00
}
2025-02-05 12:55:02 +00:00
FlexWrap ComputedProperties : : flex_wrap ( ) const
2021-05-30 12:11:32 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : FlexWrap ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_flex_wrap ( value . to_keyword ( ) ) . release_value ( ) ;
2021-05-30 12:11:32 +02:00
}
2025-02-05 12:55:02 +00:00
FlexBasis ComputedProperties : : flex_basis ( ) const
2021-05-30 14:23:43 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : FlexBasis ) ;
2021-05-30 14:23:43 +02:00
2025-02-05 12:57:41 +00:00
if ( value . is_keyword ( ) & & value . to_keyword ( ) = = Keyword : : Content )
return FlexBasisContent { } ;
2021-05-30 14:23:43 +02:00
2025-02-05 12:57:41 +00:00
return size_value ( PropertyID : : FlexBasis ) ;
2021-05-30 14:23:43 +02:00
}
2024-12-20 11:32:17 +01:00
float ComputedProperties : : flex_grow ( ) const
2021-05-30 20:22:25 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : FlexGrow ) ;
2024-11-03 13:20:04 +01:00
if ( ! value . is_number ( ) )
2021-10-19 15:22:08 +02:00
return 0 ;
2024-11-03 13:20:04 +01:00
return value . as_number ( ) . number ( ) ;
2021-05-30 20:22:25 +02:00
}
2024-12-20 11:32:17 +01:00
float ComputedProperties : : flex_shrink ( ) const
2021-05-30 20:22:25 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : FlexShrink ) ;
2024-11-03 13:20:04 +01:00
if ( ! value . is_number ( ) )
2021-10-19 15:22:08 +02:00
return 1 ;
2024-11-03 13:20:04 +01:00
return value . as_number ( ) . number ( ) ;
2021-05-30 20:22:25 +02:00
}
2021-10-19 15:22:08 +02:00
2024-12-20 11:32:17 +01:00
int ComputedProperties : : order ( ) const
2022-03-31 22:11:38 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : Order ) ;
2024-11-03 13:20:04 +01:00
if ( ! value . is_integer ( ) )
2022-03-31 22:11:38 +02:00
return 0 ;
2024-11-03 13:20:04 +01:00
return value . as_integer ( ) . integer ( ) ;
2022-03-31 22:11:38 +02:00
}
2025-02-05 12:55:02 +00:00
ImageRendering ComputedProperties : : image_rendering ( ) const
2022-02-18 12:21:27 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : ImageRendering ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_image_rendering ( value . to_keyword ( ) ) . release_value ( ) ;
2022-02-18 12:21:27 +01:00
}
2025-02-05 12:57:41 +00:00
Length ComputedProperties : : border_spacing_horizontal ( Layout : : Node const & layout_node ) const
2023-06-16 02:35:03 +00:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : BorderSpacing ) ;
2024-11-03 13:20:04 +01:00
if ( value . is_length ( ) )
return value . as_length ( ) . length ( ) ;
2024-12-11 15:05:56 +00:00
if ( value . is_calculated ( ) )
2025-02-05 12:57:41 +00:00
return value . as_calculated ( ) . resolve_length ( { . length_resolution_context = Length : : ResolutionContext : : for_layout_node ( layout_node ) } ) . value_or ( Length ( 0 , Length : : Type : : Px ) ) ;
2024-11-03 13:20:04 +01:00
auto const & list = value . as_value_list ( ) ;
2023-06-16 02:35:03 +00:00
return list . value_at ( 0 , false ) - > as_length ( ) . length ( ) ;
}
2025-02-05 12:57:41 +00:00
Length ComputedProperties : : border_spacing_vertical ( Layout : : Node const & layout_node ) const
2023-06-16 02:35:03 +00:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : BorderSpacing ) ;
2024-11-03 13:20:04 +01:00
if ( value . is_length ( ) )
return value . as_length ( ) . length ( ) ;
2024-12-11 15:05:56 +00:00
if ( value . is_calculated ( ) )
2025-02-05 12:57:41 +00:00
return value . as_calculated ( ) . resolve_length ( { . length_resolution_context = Length : : ResolutionContext : : for_layout_node ( layout_node ) } ) . value_or ( Length ( 0 , Length : : Type : : Px ) ) ;
2024-11-03 13:20:04 +01:00
auto const & list = value . as_value_list ( ) ;
2023-06-16 02:35:03 +00:00
return list . value_at ( 1 , false ) - > as_length ( ) . length ( ) ;
}
2025-02-05 12:55:02 +00:00
CaptionSide ComputedProperties : : caption_side ( ) const
2023-06-07 02:10:55 +00:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : CaptionSide ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_caption_side ( value . to_keyword ( ) ) . release_value ( ) ;
2023-06-07 02:10:55 +00:00
}
2025-02-05 12:57:41 +00:00
Clip ComputedProperties : : clip ( ) const
2022-07-31 18:47:09 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : Clip ) ;
2024-11-03 13:20:04 +01:00
if ( ! value . is_rect ( ) )
2025-02-05 12:57:41 +00:00
return Clip : : make_auto ( ) ;
return Clip ( value . as_rect ( ) . rect ( ) ) ;
2022-07-31 18:47:09 +02:00
}
2025-02-05 12:55:02 +00:00
JustifyContent ComputedProperties : : justify_content ( ) const
2021-07-16 18:38:26 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : JustifyContent ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_justify_content ( value . to_keyword ( ) ) . release_value ( ) ;
2021-07-16 18:38:26 +02:00
}
2021-05-30 20:22:25 +02:00
2025-02-05 12:55:02 +00:00
JustifyItems ComputedProperties : : justify_items ( ) const
2023-07-14 20:49:22 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : JustifyItems ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_justify_items ( value . to_keyword ( ) ) . release_value ( ) ;
2023-07-14 20:49:22 +02:00
}
2025-02-05 12:55:02 +00:00
JustifySelf ComputedProperties : : justify_self ( ) const
2023-07-14 14:41:22 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : JustifySelf ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_justify_self ( value . to_keyword ( ) ) . release_value ( ) ;
2023-07-14 14:41:22 +02:00
}
2025-01-15 16:03:06 +00:00
Vector < Transformation > ComputedProperties : : transformations_for_style_value ( CSSStyleValue const & value )
2021-09-18 17:20:00 +02:00
{
2025-02-05 12:57:41 +00:00
if ( value . is_keyword ( ) & & value . to_keyword ( ) = = Keyword : : None )
2021-09-18 17:20:00 +02:00
return { } ;
2024-01-06 18:05:21 +01:00
if ( ! value . is_value_list ( ) )
2021-09-18 17:20:00 +02:00
return { } ;
2024-01-06 18:05:21 +01:00
auto & list = value . as_value_list ( ) ;
2021-09-18 17:20:00 +02:00
2025-01-15 16:03:06 +00:00
Vector < Transformation > transformations ;
2021-09-18 17:20:00 +02:00
for ( auto & it : list . values ( ) ) {
2023-03-06 14:33:11 +01:00
if ( ! it - > is_transformation ( ) )
2021-09-18 17:20:00 +02:00
return { } ;
2025-01-15 16:03:06 +00:00
transformations . append ( it - > as_transformation ( ) . to_transformation ( ) ) ;
2021-09-18 17:20:00 +02:00
}
return transformations ;
}
2025-02-05 12:57:41 +00:00
Vector < Transformation > ComputedProperties : : transformations ( ) const
2024-01-06 18:05:21 +01:00
{
2025-02-05 12:57:41 +00:00
return transformations_for_style_value ( property ( PropertyID : : Transform ) ) ;
2024-01-06 18:05:21 +01:00
}
2025-01-15 17:21:22 +00:00
Optional < Transformation > ComputedProperties : : rotate ( ) const
2024-10-16 08:50:35 +02:00
{
2025-01-15 17:21:22 +00:00
auto const & value = property ( PropertyID : : Rotate ) ;
if ( ! value . is_transformation ( ) )
2024-10-16 08:50:35 +02:00
return { } ;
2025-01-15 17:21:22 +00:00
return value . as_transformation ( ) . to_transformation ( ) ;
2024-10-16 08:50:35 +02:00
}
2025-01-15 16:48:44 +00:00
Optional < Transformation > ComputedProperties : : translate ( ) const
2024-11-22 16:42:20 +01:00
{
2025-01-15 16:48:44 +00:00
auto const & value = property ( PropertyID : : Translate ) ;
if ( ! value . is_transformation ( ) )
2024-11-22 16:42:20 +01:00
return { } ;
2025-01-15 16:48:44 +00:00
return value . as_transformation ( ) . to_transformation ( ) ;
2024-11-22 16:42:20 +01:00
}
2025-01-15 14:58:23 +00:00
Optional < Transformation > ComputedProperties : : scale ( ) const
2024-11-22 18:07:16 +01:00
{
2025-01-15 14:58:23 +00:00
auto const & value = property ( PropertyID : : Scale ) ;
if ( ! value . is_transformation ( ) )
2024-11-22 18:07:16 +01:00
return { } ;
2025-01-15 14:58:23 +00:00
return value . as_transformation ( ) . to_transformation ( ) ;
2024-11-22 18:07:16 +01:00
}
2024-08-14 11:10:54 +01:00
static Optional < LengthPercentage > length_percentage_for_style_value ( CSSStyleValue const & value )
2022-03-21 19:38:00 +01:00
{
if ( value . is_length ( ) )
2023-05-27 12:28:25 +01:00
return value . as_length ( ) . length ( ) ;
2022-03-21 19:38:00 +01:00
if ( value . is_percentage ( ) )
return value . as_percentage ( ) . percentage ( ) ;
2024-12-11 15:05:56 +00:00
if ( value . is_calculated ( ) )
2024-12-11 15:16:34 +00:00
return LengthPercentage { value . as_calculated ( ) } ;
2022-03-21 19:38:00 +01:00
return { } ;
}
2025-02-05 12:55:02 +00:00
TransformBox ComputedProperties : : transform_box ( ) const
2024-01-25 17:02:37 +00:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : TransformBox ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_transform_box ( value . to_keyword ( ) ) . release_value ( ) ;
2024-01-25 17:02:37 +00:00
}
2025-02-05 12:57:41 +00:00
TransformOrigin ComputedProperties : : transform_origin ( ) const
2022-03-21 19:38:00 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : TransformOrigin ) ;
2024-11-03 13:20:04 +01:00
if ( ! value . is_value_list ( ) | | value . as_value_list ( ) . size ( ) ! = 2 )
2022-03-21 19:38:00 +01:00
return { } ;
2024-11-03 13:20:04 +01:00
auto const & list = value . as_value_list ( ) ;
2022-03-21 19:38:00 +01:00
auto x_value = length_percentage_for_style_value ( list . values ( ) [ 0 ] ) ;
auto y_value = length_percentage_for_style_value ( list . values ( ) [ 1 ] ) ;
if ( ! x_value . has_value ( ) | | ! y_value . has_value ( ) ) {
return { } ;
}
return { x_value . value ( ) , y_value . value ( ) } ;
}
2024-12-20 11:32:17 +01:00
Optional < Color > ComputedProperties : : accent_color ( Layout : : NodeWithStyle const & node ) const
2023-03-18 20:49:00 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : AccentColor ) ;
2024-11-03 13:20:04 +01:00
if ( value . has_color ( ) )
return value . to_color ( node ) ;
2023-03-18 20:49:00 +01:00
return { } ;
}
2025-02-05 12:55:02 +00:00
AlignContent ComputedProperties : : align_content ( ) const
2022-10-14 13:50:06 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : AlignContent ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_align_content ( value . to_keyword ( ) ) . release_value ( ) ;
2022-10-14 13:50:06 +02:00
}
2025-02-05 12:55:02 +00:00
AlignItems ComputedProperties : : align_items ( ) const
2021-09-15 18:27:20 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : AlignItems ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_align_items ( value . to_keyword ( ) ) . release_value ( ) ;
2021-09-15 18:27:20 +02:00
}
2025-02-05 12:55:02 +00:00
AlignSelf ComputedProperties : : align_self ( ) const
2022-07-11 23:52:36 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : AlignSelf ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_align_self ( value . to_keyword ( ) ) . release_value ( ) ;
2022-07-11 23:52:36 +02:00
}
2025-02-05 12:55:02 +00:00
Appearance ComputedProperties : : appearance ( ) const
2022-07-22 16:05:11 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : Appearance ) ;
2025-02-05 12:55:02 +00:00
auto appearance = keyword_to_appearance ( value . to_keyword ( ) ) . release_value ( ) ;
switch ( appearance ) {
// Note: All these compatibility values can be treated as 'auto'
2025-02-05 12:57:41 +00:00
case Appearance : : Textfield :
case Appearance : : MenulistButton :
case Appearance : : Searchfield :
case Appearance : : Textarea :
case Appearance : : PushButton :
case Appearance : : SliderHorizontal :
case Appearance : : Checkbox :
case Appearance : : Radio :
case Appearance : : SquareButton :
case Appearance : : Menulist :
case Appearance : : Listbox :
case Appearance : : Meter :
case Appearance : : ProgressBar :
case Appearance : : Button :
appearance = Appearance : : Auto ;
2025-02-05 12:55:02 +00:00
break ;
default :
break ;
2022-07-22 16:05:11 +01:00
}
return appearance ;
}
2025-02-05 12:57:41 +00:00
Filter ComputedProperties : : backdrop_filter ( ) const
2022-09-15 08:31:19 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : BackdropFilter ) ;
2024-11-03 13:20:04 +01:00
if ( value . is_filter_value_list ( ) )
return Filter ( value . as_filter_value_list ( ) ) ;
2024-10-25 11:00:22 +02:00
return Filter : : make_none ( ) ;
}
2025-02-05 12:57:41 +00:00
Filter ComputedProperties : : filter ( ) const
2024-10-25 11:00:22 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : Filter ) ;
2024-11-03 13:20:04 +01:00
if ( value . is_filter_value_list ( ) )
return Filter ( value . as_filter_value_list ( ) ) ;
2024-10-25 11:00:22 +02:00
return Filter : : make_none ( ) ;
2022-09-15 08:31:19 +01:00
}
2025-02-05 12:55:02 +00:00
Positioning ComputedProperties : : position ( ) const
2020-03-23 17:29:15 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : Position ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_positioning ( value . to_keyword ( ) ) . release_value ( ) ;
2020-03-23 17:29:15 +01:00
}
2024-12-20 11:32:17 +01:00
bool ComputedProperties : : operator = = ( ComputedProperties const & other ) const
2019-10-14 18:32:02 +02:00
{
2024-12-20 16:35:12 +01:00
if ( m_property_values . size ( ) ! = other . m_property_values . size ( ) )
2019-10-14 18:32:02 +02:00
return false ;
2024-12-20 16:35:12 +01:00
for ( size_t i = 0 ; i < m_property_values . size ( ) ; + + i ) {
auto const & my_style = m_property_values [ i ] ;
auto const & other_style = other . m_property_values [ i ] ;
2024-08-02 13:59:19 +02:00
if ( ! my_style ) {
if ( other_style )
2022-02-18 20:21:49 +01:00
return false ;
continue ;
}
2024-08-02 13:59:19 +02:00
if ( ! other_style )
2019-10-14 18:32:02 +02:00
return false ;
2024-08-02 13:59:19 +02:00
auto const & my_value = * my_style ;
auto const & other_value = * other_style ;
2019-10-14 18:32:02 +02:00
if ( my_value . type ( ) ! = other_value . type ( ) )
return false ;
2020-12-14 15:56:01 +01:00
if ( my_value ! = other_value )
2019-10-14 18:32:02 +02:00
return false ;
}
return true ;
}
2020-03-07 10:27:02 +01:00
2025-02-05 12:55:02 +00:00
TextAnchor ComputedProperties : : text_anchor ( ) const
2023-07-19 19:12:00 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : TextAnchor ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_text_anchor ( value . to_keyword ( ) ) . release_value ( ) ;
2023-07-19 19:12:00 +01:00
}
2025-02-05 12:55:02 +00:00
TextAlign ComputedProperties : : text_align ( ) const
2020-06-13 10:54:58 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : TextAlign ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_text_align ( value . to_keyword ( ) ) . release_value ( ) ;
2022-03-12 19:31:32 +00:00
}
2025-02-05 12:55:02 +00:00
TextJustify ComputedProperties : : text_justify ( ) const
2022-03-12 19:31:32 +00:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : TextJustify ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_text_justify ( value . to_keyword ( ) ) . release_value ( ) ;
2020-06-13 10:54:58 +02:00
}
2025-02-05 12:55:02 +00:00
TextOverflow ComputedProperties : : text_overflow ( ) const
2024-07-24 20:58:17 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : TextOverflow ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_text_overflow ( value . to_keyword ( ) ) . release_value ( ) ;
2024-07-24 20:58:17 +02:00
}
2025-02-05 12:55:02 +00:00
PointerEvents ComputedProperties : : pointer_events ( ) const
2021-10-05 19:47:13 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : PointerEvents ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_pointer_events ( value . to_keyword ( ) ) . release_value ( ) ;
2021-10-05 19:47:13 +01:00
}
2024-12-20 11:32:17 +01:00
Variant < LengthOrCalculated , NumberOrCalculated > ComputedProperties : : tab_size ( ) const
2024-10-01 13:07:06 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : TabSize ) ;
2024-12-11 15:05:56 +00:00
if ( value . is_calculated ( ) ) {
auto const & math_value = value . as_calculated ( ) ;
2024-10-01 13:07:06 +01:00
if ( math_value . resolves_to_length ( ) ) {
return LengthOrCalculated { math_value } ;
}
if ( math_value . resolves_to_number ( ) ) {
return NumberOrCalculated { math_value } ;
}
}
2024-11-03 13:20:04 +01:00
if ( value . is_length ( ) )
return LengthOrCalculated { value . as_length ( ) . length ( ) } ;
2024-10-01 13:07:06 +01:00
2024-11-03 13:20:04 +01:00
return NumberOrCalculated { value . as_number ( ) . number ( ) } ;
2024-10-01 13:07:06 +01:00
}
2025-02-05 12:55:02 +00:00
WordBreak ComputedProperties : : word_break ( ) const
2024-10-25 16:47:05 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : WordBreak ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_word_break ( value . to_keyword ( ) ) . release_value ( ) ;
2024-10-25 16:47:05 +01:00
}
2025-02-05 12:55:02 +00:00
Optional < LengthOrCalculated > ComputedProperties : : word_spacing ( ) const
2024-10-18 21:00:28 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : WordSpacing ) ;
2024-12-11 15:05:56 +00:00
if ( value . is_calculated ( ) ) {
auto & math_value = value . as_calculated ( ) ;
2024-10-18 21:00:28 +01:00
if ( math_value . resolves_to_length ( ) ) {
return LengthOrCalculated { math_value } ;
}
}
2024-11-03 13:20:04 +01:00
if ( value . is_length ( ) )
return LengthOrCalculated { value . as_length ( ) . length ( ) } ;
2024-10-18 21:00:28 +01:00
return { } ;
}
2025-02-05 12:55:02 +00:00
WhiteSpace ComputedProperties : : white_space ( ) const
2020-06-24 16:37:44 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : WhiteSpace ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_white_space ( value . to_keyword ( ) ) . release_value ( ) ;
2020-06-24 16:37:44 +02:00
}
2024-12-20 11:32:17 +01:00
Optional < LengthOrCalculated > ComputedProperties : : letter_spacing ( ) const
2024-10-22 14:21:20 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : LetterSpacing ) ;
2024-12-11 15:05:56 +00:00
if ( value . is_calculated ( ) ) {
auto const & math_value = value . as_calculated ( ) ;
2024-10-22 14:21:20 +01:00
if ( math_value . resolves_to_length ( ) ) {
return LengthOrCalculated { math_value } ;
}
}
2024-11-03 13:20:04 +01:00
if ( value . is_length ( ) )
return LengthOrCalculated { value . as_length ( ) . length ( ) } ;
2024-10-22 14:21:20 +01:00
return { } ;
}
2025-02-05 12:57:41 +00:00
LineStyle ComputedProperties : : line_style ( PropertyID property_id ) const
2020-12-04 16:11:55 +01:00
{
2024-11-03 13:20:04 +01:00
auto const & value = property ( property_id ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_line_style ( value . to_keyword ( ) ) . release_value ( ) ;
2023-08-02 17:24:14 +01:00
}
2025-02-05 12:55:02 +00:00
OutlineStyle ComputedProperties : : outline_style ( ) const
2023-08-02 17:24:14 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : OutlineStyle ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_outline_style ( value . to_keyword ( ) ) . release_value ( ) ;
2020-12-04 16:11:55 +01:00
}
2025-02-05 12:55:02 +00:00
Float ComputedProperties : : float_ ( ) const
2020-06-26 15:08:42 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : Float ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_float ( value . to_keyword ( ) ) . release_value ( ) ;
2020-06-26 15:08:42 +02:00
}
2025-02-05 12:55:02 +00:00
Clear ComputedProperties : : clear ( ) const
2020-12-06 01:45:51 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : Clear ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_clear ( value . to_keyword ( ) ) . release_value ( ) ;
2020-12-06 01:45:51 +01:00
}
2025-02-05 12:55:02 +00:00
ColumnSpan ComputedProperties : : column_span ( ) const
2024-08-20 20:23:55 -04:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : ColumnSpan ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_column_span ( value . to_keyword ( ) ) . release_value ( ) ;
2024-08-20 20:23:55 -04:00
}
2024-12-20 11:32:17 +01:00
ComputedProperties : : ContentDataAndQuoteNestingLevel ComputedProperties : : content ( DOM : : Element & element , u32 initial_quote_nesting_level ) const
2022-02-24 16:52:58 +00:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : Content ) ;
2023-09-12 14:22:46 +01:00
auto quotes_data = quotes ( ) ;
2023-09-18 15:41:17 +01:00
auto quote_nesting_level = initial_quote_nesting_level ;
2023-09-12 14:22:46 +01:00
auto get_quote_string = [ & ] ( bool open , auto depth ) {
switch ( quotes_data . type ) {
case QuotesData : : Type : : None :
2024-07-17 12:42:12 +01:00
return FlyString { } ;
2023-09-12 14:22:46 +01:00
case QuotesData : : Type : : Auto :
// FIXME: "A typographically appropriate used value for quotes is automatically chosen by the UA
// based on the content language of the element and/or its parent."
if ( open )
2024-07-17 12:42:12 +01:00
return depth = = 0 ? " “ " _fly_string : " ‘ " _fly_string ;
return depth = = 0 ? " ” " _fly_string : " ’ " _fly_string ;
2023-09-12 14:22:46 +01:00
case QuotesData : : Type : : Specified :
2023-09-18 15:28:40 +01:00
// If the depth is greater than the number of pairs, the last pair is repeated.
auto & level = quotes_data . strings [ min ( depth , quotes_data . strings . size ( ) - 1 ) ] ;
2023-09-12 14:22:46 +01:00
return open ? level [ 0 ] : level [ 1 ] ;
}
VERIFY_NOT_REACHED ( ) ;
} ;
2024-11-03 13:20:04 +01:00
if ( value . is_content ( ) ) {
auto & content_style_value = value . as_content ( ) ;
2022-02-24 16:52:58 +00:00
2025-02-05 12:57:41 +00:00
ContentData content_data ;
2022-02-24 16:52:58 +00:00
// FIXME: The content is a list of things: strings, identifiers or functions that return strings, and images.
// So it can't always be represented as a single String, but may have to be multiple boxes.
// For now, we'll just assume strings since that is easiest.
StringBuilder builder ;
for ( auto const & item : content_style_value . content ( ) . values ( ) ) {
2023-03-06 14:33:11 +01:00
if ( item - > is_string ( ) ) {
2023-09-12 11:33:11 +01:00
builder . append ( item - > as_string ( ) . string_value ( ) ) ;
2024-08-14 11:46:56 +01:00
} else if ( item - > is_keyword ( ) ) {
2024-08-14 14:06:03 +01:00
switch ( item - > to_keyword ( ) ) {
case Keyword : : OpenQuote :
2023-09-18 15:41:17 +01:00
builder . append ( get_quote_string ( true , quote_nesting_level + + ) ) ;
2023-09-12 14:22:46 +01:00
break ;
2024-08-14 14:06:03 +01:00
case Keyword : : CloseQuote :
2023-09-18 15:41:17 +01:00
// A 'close-quote' or 'no-close-quote' that would make the depth negative is in error and is ignored
// (at rendering time): the depth stays at 0 and no quote mark is rendered (although the rest of the
// 'content' property's value is still inserted).
// - https://www.w3.org/TR/CSS21/generate.html#quotes-insert
// (This is missing from the CONTENT-3 spec.)
if ( quote_nesting_level > 0 )
builder . append ( get_quote_string ( false , - - quote_nesting_level ) ) ;
2023-09-12 14:22:46 +01:00
break ;
2024-08-14 14:06:03 +01:00
case Keyword : : NoOpenQuote :
2023-09-18 15:41:17 +01:00
quote_nesting_level + + ;
2023-09-12 14:22:46 +01:00
break ;
2024-08-14 14:06:03 +01:00
case Keyword : : NoCloseQuote :
2023-09-18 15:41:17 +01:00
// NOTE: See CloseQuote
if ( quote_nesting_level > 0 )
quote_nesting_level - - ;
2023-09-12 14:22:46 +01:00
break ;
default :
2024-12-07 00:59:49 +01:00
dbgln ( " `{}` is not supported in `content` (yet?) " , item - > to_string ( CSSStyleValue : : SerializationMode : : Normal ) ) ;
2023-09-12 14:22:46 +01:00
break ;
}
2024-07-18 20:29:02 +01:00
} else if ( item - > is_counter ( ) ) {
builder . append ( item - > as_counter ( ) . resolve ( element ) ) ;
2022-02-24 16:52:58 +00:00
} else {
2024-07-18 20:29:02 +01:00
// TODO: Implement images, and other things.
2024-12-07 00:59:49 +01:00
dbgln ( " `{}` is not supported in `content` (yet?) " , item - > to_string ( CSSStyleValue : : SerializationMode : : Normal ) ) ;
2022-02-24 16:52:58 +00:00
}
}
content_data . type = ContentData : : Type : : String ;
2023-09-12 14:22:46 +01:00
content_data . data = MUST ( builder . to_string ( ) ) ;
2022-02-24 16:52:58 +00:00
if ( content_style_value . has_alt_text ( ) ) {
StringBuilder alt_text_builder ;
for ( auto const & item : content_style_value . alt_text ( ) - > values ( ) ) {
2023-03-06 14:33:11 +01:00
if ( item - > is_string ( ) ) {
2023-09-12 11:33:11 +01:00
alt_text_builder . append ( item - > as_string ( ) . string_value ( ) ) ;
2024-07-18 20:29:02 +01:00
} else if ( item - > is_counter ( ) ) {
alt_text_builder . append ( item - > as_counter ( ) . resolve ( element ) ) ;
2022-02-24 16:52:58 +00:00
} else {
2024-12-07 00:59:49 +01:00
dbgln ( " `{}` is not supported in `content` alt-text (yet?) " , item - > to_string ( CSSStyleValue : : SerializationMode : : Normal ) ) ;
2022-02-24 16:52:58 +00:00
}
}
2023-09-12 14:22:46 +01:00
content_data . alt_text = MUST ( alt_text_builder . to_string ( ) ) ;
2022-02-24 16:52:58 +00:00
}
2023-09-18 15:41:17 +01:00
return { content_data , quote_nesting_level } ;
2022-02-24 16:52:58 +00:00
}
2024-11-03 13:20:04 +01:00
switch ( value . to_keyword ( ) ) {
2024-08-14 14:06:03 +01:00
case Keyword : : None :
2023-09-18 15:41:17 +01:00
return { { ContentData : : Type : : None } , quote_nesting_level } ;
2024-08-14 14:06:03 +01:00
case Keyword : : Normal :
2023-09-18 15:41:17 +01:00
return { { ContentData : : Type : : Normal } , quote_nesting_level } ;
2022-02-24 16:52:58 +00:00
default :
break ;
}
2023-09-18 15:41:17 +01:00
return { { } , quote_nesting_level } ;
2022-02-24 16:52:58 +00:00
}
2025-02-05 12:55:02 +00:00
ContentVisibility ComputedProperties : : content_visibility ( ) const
2024-06-23 14:52:56 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : ContentVisibility ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_content_visibility ( value . to_keyword ( ) ) . release_value ( ) ;
2024-06-23 14:52:56 +02:00
}
2025-02-05 12:55:02 +00:00
Cursor ComputedProperties : : cursor ( ) const
2021-02-21 17:41:00 +00:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : Cursor ) ;
2025-02-14 20:58:38 +11:00
// FIXME: We don't currently support custom cursors.
if ( value . is_url ( ) )
return Cursor : : Auto ;
2025-02-05 12:55:02 +00:00
return keyword_to_cursor ( value . to_keyword ( ) ) . release_value ( ) ;
2021-02-21 17:41:00 +00:00
}
2025-02-05 12:55:02 +00:00
Visibility ComputedProperties : : visibility ( ) const
2022-03-21 15:42:57 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : Visibility ) ;
2024-11-03 13:20:04 +01:00
if ( ! value . is_keyword ( ) )
2022-03-21 15:42:57 +01:00
return { } ;
2025-02-05 12:55:02 +00:00
return keyword_to_visibility ( value . to_keyword ( ) ) . release_value ( ) ;
2022-03-21 15:42:57 +01:00
}
2024-12-20 11:32:17 +01:00
Display ComputedProperties : : display ( ) const
2020-06-24 16:22:16 +02:00
{
2024-11-03 13:20:04 +01:00
auto const & value = property ( PropertyID : : Display ) ;
if ( value . is_display ( ) ) {
return value . as_display ( ) . display ( ) ;
2020-12-14 22:22:35 +01:00
}
2023-04-26 21:05:38 +02:00
return Display : : from_short ( Display : : Short : : Inline ) ;
2020-06-24 16:22:16 +02:00
}
2025-02-05 12:57:41 +00:00
Vector < TextDecorationLine > ComputedProperties : : text_decoration_line ( ) const
2020-12-15 13:36:27 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : TextDecorationLine ) ;
2022-04-14 16:22:35 +01:00
2024-11-03 13:20:04 +01:00
if ( value . is_value_list ( ) ) {
2025-02-05 12:57:41 +00:00
Vector < TextDecorationLine > lines ;
2024-11-03 13:20:04 +01:00
auto & values = value . as_value_list ( ) . values ( ) ;
2022-04-14 16:22:35 +01:00
for ( auto const & item : values ) {
2024-08-14 14:06:03 +01:00
lines . append ( keyword_to_text_decoration_line ( item - > to_keyword ( ) ) . value ( ) ) ;
2022-04-14 16:22:35 +01:00
}
return lines ;
}
2024-11-03 13:20:04 +01:00
if ( value . is_keyword ( ) & & value . to_keyword ( ) = = Keyword : : None )
2022-04-14 16:22:35 +01:00
return { } ;
2024-12-07 00:59:49 +01:00
dbgln ( " FIXME: Unsupported value for text-decoration-line: {} " , value . to_string ( CSSStyleValue : : SerializationMode : : Normal ) ) ;
2022-11-02 19:07:17 +01:00
return { } ;
2020-12-15 13:36:27 +01:00
}
2025-02-05 12:55:02 +00:00
TextDecorationStyle ComputedProperties : : text_decoration_style ( ) const
2022-01-20 20:27:55 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : TextDecorationStyle ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_text_decoration_style ( value . to_keyword ( ) ) . release_value ( ) ;
2022-01-20 20:27:55 +01:00
}
2025-02-05 12:55:02 +00:00
TextTransform ComputedProperties : : text_transform ( ) const
2020-12-15 14:15:49 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : TextTransform ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_text_transform ( value . to_keyword ( ) ) . release_value ( ) ;
2020-12-15 14:15:49 +01:00
}
2025-02-05 12:55:02 +00:00
ListStyleType ComputedProperties : : list_style_type ( ) const
2020-12-15 16:50:39 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : ListStyleType ) ;
2025-02-10 12:48:40 +00:00
if ( value . is_string ( ) )
return value . as_string ( ) . string_value ( ) . to_string ( ) ;
return keyword_to_counter_style_name_keyword ( value . to_keyword ( ) ) . release_value ( ) ;
2020-12-15 16:50:39 +01:00
}
2025-02-05 12:55:02 +00:00
ListStylePosition ComputedProperties : : list_style_position ( ) const
2023-06-02 23:05:15 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : ListStylePosition ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_list_style_position ( value . to_keyword ( ) ) . release_value ( ) ;
2023-06-02 23:05:15 +02:00
}
2025-02-05 12:55:02 +00:00
Overflow ComputedProperties : : overflow_x ( ) const
2021-02-22 15:20:31 +01:00
{
2025-02-05 12:57:41 +00:00
return overflow ( PropertyID : : OverflowX ) ;
2021-02-22 15:20:31 +01:00
}
2025-02-05 12:55:02 +00:00
Overflow ComputedProperties : : overflow_y ( ) const
2021-02-22 15:20:31 +01:00
{
2025-02-05 12:57:41 +00:00
return overflow ( PropertyID : : OverflowY ) ;
2021-02-22 15:20:31 +01:00
}
2025-02-05 12:57:41 +00:00
Overflow ComputedProperties : : overflow ( PropertyID property_id ) const
2021-02-22 15:20:31 +01:00
{
2024-11-03 13:20:04 +01:00
auto const & value = property ( property_id ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_overflow ( value . to_keyword ( ) ) . release_value ( ) ;
2021-02-22 15:20:31 +01:00
}
2024-12-20 11:32:17 +01:00
Vector < ShadowData > ComputedProperties : : shadow ( PropertyID property_id , Layout : : Node const & layout_node ) const
2021-07-23 21:22:31 +02:00
{
2024-11-03 13:20:04 +01:00
auto const & value = property ( property_id ) ;
2021-07-23 21:22:31 +02:00
2024-08-14 11:10:54 +01:00
auto resolve_to_length = [ & layout_node ] ( NonnullRefPtr < CSSStyleValue const > const & value ) - > Optional < Length > {
2023-05-31 16:07:06 -04:00
if ( value - > is_length ( ) )
return value - > as_length ( ) . length ( ) ;
2024-12-11 15:05:56 +00:00
if ( value - > is_calculated ( ) )
LibWeb/CSS: Wrap calc()-resolution data in a struct
Initially I added this to the existing CalculationContext, but in
reality, we have some data at parse-time and different data at
resolve-time, so it made more sense to keep those separate.
Instead of needing a variety of methods for resolving a Foo, depending
on whether we have a Layout::Node available, or a percentage basis, or
a length resolution context... put those in a
CalculationResolutionContext, and just pass that one thing to these
methods. This also removes the need for separate resolve_*_percentage()
methods, because we can just pass the percentage basis in to the regular
resolve_foo() method.
This also corrects the issue that *any* calculation may need to resolve
lengths, but we previously only passed a length resolution context to
specific types in some situations. Now, they can all have one available,
though it's up to the caller to provide it.
2025-01-22 16:05:32 +00:00
return value - > as_calculated ( ) . resolve_length ( { . length_resolution_context = Length : : ResolutionContext : : for_layout_node ( layout_node ) } ) ;
2023-05-31 16:07:06 -04:00
return { } ;
} ;
2024-08-15 11:06:18 +01:00
auto make_shadow_data = [ resolve_to_length , & layout_node ] ( ShadowStyleValue const & value ) - > Optional < ShadowData > {
2023-05-31 16:07:06 -04:00
auto maybe_offset_x = resolve_to_length ( value . offset_x ( ) ) ;
if ( ! maybe_offset_x . has_value ( ) )
return { } ;
auto maybe_offset_y = resolve_to_length ( value . offset_y ( ) ) ;
if ( ! maybe_offset_y . has_value ( ) )
return { } ;
auto maybe_blur_radius = resolve_to_length ( value . blur_radius ( ) ) ;
if ( ! maybe_blur_radius . has_value ( ) )
return { } ;
auto maybe_spread_distance = resolve_to_length ( value . spread_distance ( ) ) ;
if ( ! maybe_spread_distance . has_value ( ) )
return { } ;
return ShadowData {
maybe_offset_x . release_value ( ) ,
maybe_offset_y . release_value ( ) ,
maybe_blur_radius . release_value ( ) ,
maybe_spread_distance . release_value ( ) ,
2025-01-21 09:12:05 -05:00
value . color ( ) - > to_color ( as < Layout : : NodeWithStyle > ( layout_node ) ) ,
2023-05-31 16:07:06 -04:00
value . placement ( )
} ;
2022-02-08 14:48:37 +00:00
} ;
2024-11-03 13:20:04 +01:00
if ( value . is_value_list ( ) ) {
auto const & value_list = value . as_value_list ( ) ;
2022-02-08 14:48:37 +00:00
2022-03-23 21:16:36 +00:00
Vector < ShadowData > shadow_data ;
shadow_data . ensure_capacity ( value_list . size ( ) ) ;
2023-05-31 16:07:06 -04:00
for ( auto const & layer_value : value_list . values ( ) ) {
auto maybe_shadow_data = make_shadow_data ( layer_value - > as_shadow ( ) ) ;
if ( ! maybe_shadow_data . has_value ( ) )
return { } ;
shadow_data . append ( maybe_shadow_data . release_value ( ) ) ;
}
2022-02-08 14:48:37 +00:00
2022-03-23 21:16:36 +00:00
return shadow_data ;
2022-02-08 14:48:37 +00:00
}
2024-11-03 13:20:04 +01:00
if ( value . is_shadow ( ) ) {
auto maybe_shadow_data = make_shadow_data ( value . as_shadow ( ) ) ;
2023-05-31 16:07:06 -04:00
if ( ! maybe_shadow_data . has_value ( ) )
return { } ;
return { maybe_shadow_data . release_value ( ) } ;
2022-02-08 14:48:37 +00:00
}
return { } ;
2021-07-23 21:22:31 +02:00
}
2021-10-05 16:55:02 +01:00
2024-12-20 11:32:17 +01:00
Vector < ShadowData > ComputedProperties : : box_shadow ( Layout : : Node const & layout_node ) const
2022-03-23 21:16:36 +00:00
{
2023-05-31 16:07:06 -04:00
return shadow ( PropertyID : : BoxShadow , layout_node ) ;
2022-03-23 21:16:36 +00:00
}
2024-12-20 11:32:17 +01:00
Vector < ShadowData > ComputedProperties : : text_shadow ( Layout : : Node const & layout_node ) const
2022-03-23 21:16:36 +00:00
{
2023-05-31 16:07:06 -04:00
return shadow ( PropertyID : : TextShadow , layout_node ) ;
2022-03-23 21:16:36 +00:00
}
2025-02-05 12:55:02 +00:00
BoxSizing ComputedProperties : : box_sizing ( ) const
2021-10-05 16:55:02 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : BoxSizing ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_box_sizing ( value . to_keyword ( ) ) . release_value ( ) ;
2021-10-05 16:55:02 +01:00
}
2022-02-26 01:34:07 +01:00
2025-02-05 12:57:41 +00:00
Variant < VerticalAlign , LengthPercentage > ComputedProperties : : vertical_align ( ) const
2022-02-26 01:34:07 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : VerticalAlign ) ;
2022-02-26 01:34:07 +01:00
2024-11-03 13:20:04 +01:00
if ( value . is_keyword ( ) )
return keyword_to_vertical_align ( value . to_keyword ( ) ) . release_value ( ) ;
2022-02-26 01:34:07 +01:00
2024-11-03 13:20:04 +01:00
if ( value . is_length ( ) )
2025-02-05 12:57:41 +00:00
return LengthPercentage ( value . as_length ( ) . length ( ) ) ;
2022-02-26 01:34:07 +01:00
2024-11-03 13:20:04 +01:00
if ( value . is_percentage ( ) )
2025-02-05 12:57:41 +00:00
return LengthPercentage ( value . as_percentage ( ) . percentage ( ) ) ;
2022-02-26 01:34:07 +01:00
2024-12-11 15:05:56 +00:00
if ( value . is_calculated ( ) )
2024-12-11 15:16:34 +00:00
return LengthPercentage { value . as_calculated ( ) } ;
2023-06-17 00:09:41 +02:00
2022-02-26 01:34:07 +01:00
VERIFY_NOT_REACHED ( ) ;
}
2024-12-20 11:32:17 +01:00
Optional < FlyString > ComputedProperties : : font_language_override ( ) const
2024-09-27 17:11:05 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : FontLanguageOverride ) ;
2024-11-03 13:20:04 +01:00
if ( value . is_string ( ) )
return value . as_string ( ) . string_value ( ) ;
2024-09-27 17:11:05 +01:00
return { } ;
}
2024-12-20 11:32:17 +01:00
Optional < Gfx : : FontVariantAlternates > ComputedProperties : : font_variant_alternates ( ) const
2024-12-05 01:19:03 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : FontVariantAlternates ) ;
2025-02-10 14:32:58 +00:00
switch ( keyword_to_font_variant_alternates ( value . to_keyword ( ) ) . value ( ) ) {
case FontVariantAlternates : : Normal :
return { } ;
case FontVariantAlternates : : HistoricalForms :
return Gfx : : FontVariantAlternates { . historical_forms = true } ;
}
VERIFY_NOT_REACHED ( ) ;
2024-12-05 01:19:03 +01:00
}
2025-02-05 12:55:02 +00:00
FontVariantCaps ComputedProperties : : font_variant_caps ( ) const
2024-12-05 01:19:03 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : FontVariantCaps ) ;
2025-02-10 14:32:58 +00:00
return keyword_to_font_variant_caps ( value . to_keyword ( ) ) . release_value ( ) ;
2024-12-05 01:19:03 +01:00
}
2024-12-20 11:32:17 +01:00
Optional < Gfx : : FontVariantEastAsian > ComputedProperties : : font_variant_east_asian ( ) const
2024-12-05 01:19:03 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : FontVariantEastAsian ) ;
2025-02-10 14:32:58 +00:00
Gfx : : FontVariantEastAsian east_asian { } ;
bool normal = false ;
auto apply_keyword = [ & east_asian , & normal ] ( Keyword keyword ) {
switch ( keyword ) {
case Keyword : : Normal :
normal = true ;
break ;
case Keyword : : Jis78 :
east_asian . variant = Gfx : : FontVariantEastAsian : : Variant : : Jis78 ;
break ;
case Keyword : : Jis83 :
east_asian . variant = Gfx : : FontVariantEastAsian : : Variant : : Jis83 ;
break ;
case Keyword : : Jis90 :
east_asian . variant = Gfx : : FontVariantEastAsian : : Variant : : Jis90 ;
break ;
case Keyword : : Jis04 :
east_asian . variant = Gfx : : FontVariantEastAsian : : Variant : : Jis04 ;
break ;
case Keyword : : Simplified :
east_asian . variant = Gfx : : FontVariantEastAsian : : Variant : : Simplified ;
break ;
case Keyword : : Traditional :
east_asian . variant = Gfx : : FontVariantEastAsian : : Variant : : Traditional ;
break ;
case Keyword : : FullWidth :
east_asian . width = Gfx : : FontVariantEastAsian : : Width : : FullWidth ;
break ;
case Keyword : : ProportionalWidth :
east_asian . width = Gfx : : FontVariantEastAsian : : Width : : Proportional ;
break ;
case Keyword : : Ruby :
east_asian . ruby = true ;
break ;
default :
VERIFY_NOT_REACHED ( ) ;
}
} ;
if ( value . is_keyword ( ) ) {
apply_keyword ( value . to_keyword ( ) ) ;
} else if ( value . is_value_list ( ) ) {
for ( auto & child_value : value . as_value_list ( ) . values ( ) ) {
apply_keyword ( child_value - > to_keyword ( ) ) ;
}
}
if ( normal )
return { } ;
return east_asian ;
2024-12-05 01:19:03 +01:00
}
2025-02-05 12:55:02 +00:00
FontVariantEmoji ComputedProperties : : font_variant_emoji ( ) const
2024-12-05 01:19:03 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : FontVariantEmoji ) ;
2025-02-10 14:32:58 +00:00
return keyword_to_font_variant_emoji ( value . to_keyword ( ) ) . release_value ( ) ;
2024-12-05 01:19:03 +01:00
}
2024-12-20 11:32:17 +01:00
Optional < Gfx : : FontVariantLigatures > ComputedProperties : : font_variant_ligatures ( ) const
2024-12-05 01:19:03 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : FontVariantLigatures ) ;
2025-02-10 14:32:58 +00:00
Gfx : : FontVariantLigatures ligatures { } ;
bool normal = false ;
auto apply_keyword = [ & ligatures , & normal ] ( Keyword keyword ) {
switch ( keyword ) {
case Keyword : : Normal :
normal = true ;
break ;
case Keyword : : None :
ligatures . none = true ;
break ;
case Keyword : : CommonLigatures :
ligatures . common = Gfx : : FontVariantLigatures : : Common : : Common ;
break ;
case Keyword : : NoCommonLigatures :
ligatures . common = Gfx : : FontVariantLigatures : : Common : : NoCommon ;
break ;
case Keyword : : DiscretionaryLigatures :
ligatures . discretionary = Gfx : : FontVariantLigatures : : Discretionary : : Discretionary ;
break ;
case Keyword : : NoDiscretionaryLigatures :
ligatures . discretionary = Gfx : : FontVariantLigatures : : Discretionary : : NoDiscretionary ;
break ;
case Keyword : : HistoricalLigatures :
ligatures . historical = Gfx : : FontVariantLigatures : : Historical : : Historical ;
break ;
case Keyword : : NoHistoricalLigatures :
ligatures . historical = Gfx : : FontVariantLigatures : : Historical : : NoHistorical ;
break ;
case Keyword : : Contextual :
ligatures . contextual = Gfx : : FontVariantLigatures : : Contextual : : Contextual ;
break ;
case Keyword : : NoContextual :
ligatures . contextual = Gfx : : FontVariantLigatures : : Contextual : : NoContextual ;
break ;
default :
VERIFY_NOT_REACHED ( ) ;
}
} ;
if ( value . is_keyword ( ) ) {
apply_keyword ( value . to_keyword ( ) ) ;
} else if ( value . is_value_list ( ) ) {
for ( auto & child_value : value . as_value_list ( ) . values ( ) ) {
apply_keyword ( child_value - > to_keyword ( ) ) ;
}
}
if ( normal )
return { } ;
return ligatures ;
2024-12-05 01:19:03 +01:00
}
2024-12-20 11:32:17 +01:00
Optional < Gfx : : FontVariantNumeric > ComputedProperties : : font_variant_numeric ( ) const
2024-12-05 01:19:03 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : FontVariantNumeric ) ;
2025-02-10 14:32:58 +00:00
Gfx : : FontVariantNumeric numeric { } ;
bool normal = false ;
auto apply_keyword = [ & numeric , & normal ] ( Keyword keyword ) {
switch ( keyword ) {
case Keyword : : Normal :
normal = true ;
break ;
case Keyword : : Ordinal :
numeric . ordinal = true ;
break ;
case Keyword : : SlashedZero :
numeric . slashed_zero = true ;
break ;
case Keyword : : OldstyleNums :
numeric . figure = Gfx : : FontVariantNumeric : : Figure : : Oldstyle ;
break ;
case Keyword : : LiningNums :
numeric . figure = Gfx : : FontVariantNumeric : : Figure : : Lining ;
break ;
case Keyword : : ProportionalNums :
numeric . spacing = Gfx : : FontVariantNumeric : : Spacing : : Proportional ;
break ;
case Keyword : : TabularNums :
numeric . spacing = Gfx : : FontVariantNumeric : : Spacing : : Tabular ;
break ;
case Keyword : : DiagonalFractions :
numeric . fraction = Gfx : : FontVariantNumeric : : Fraction : : Diagonal ;
break ;
case Keyword : : StackedFractions :
numeric . fraction = Gfx : : FontVariantNumeric : : Fraction : : Stacked ;
break ;
default :
VERIFY_NOT_REACHED ( ) ;
}
} ;
if ( value . is_keyword ( ) ) {
apply_keyword ( value . to_keyword ( ) ) ;
} else if ( value . is_value_list ( ) ) {
for ( auto & child_value : value . as_value_list ( ) . values ( ) ) {
apply_keyword ( child_value - > to_keyword ( ) ) ;
}
}
if ( normal )
return { } ;
return numeric ;
2024-12-05 01:19:03 +01:00
}
2025-02-05 12:55:02 +00:00
FontVariantPosition ComputedProperties : : font_variant_position ( ) const
2024-12-05 01:19:03 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : FontVariantPosition ) ;
2025-02-10 14:32:58 +00:00
return keyword_to_font_variant_position ( value . to_keyword ( ) ) . release_value ( ) ;
2024-12-05 01:19:03 +01:00
}
2024-12-20 11:32:17 +01:00
Optional < HashMap < FlyString , IntegerOrCalculated > > ComputedProperties : : font_feature_settings ( ) const
2024-10-01 09:37:43 +01:00
{
2024-11-03 13:20:04 +01:00
auto const & value = property ( PropertyID : : FontFeatureSettings ) ;
2024-10-01 09:37:43 +01:00
2024-11-03 13:20:04 +01:00
if ( value . is_keyword ( ) )
2024-10-01 09:37:43 +01:00
return { } ; // normal
2024-11-03 13:20:04 +01:00
if ( value . is_value_list ( ) ) {
auto const & feature_tags = value . as_value_list ( ) . values ( ) ;
2024-10-01 09:37:43 +01:00
HashMap < FlyString , IntegerOrCalculated > result ;
result . ensure_capacity ( feature_tags . size ( ) ) ;
for ( auto const & tag_value : feature_tags ) {
auto const & feature_tag = tag_value - > as_open_type_tagged ( ) ;
if ( feature_tag . value ( ) - > is_integer ( ) ) {
result . set ( feature_tag . tag ( ) , feature_tag . value ( ) - > as_integer ( ) . value ( ) ) ;
} else {
2024-12-11 15:05:56 +00:00
VERIFY ( feature_tag . value ( ) - > is_calculated ( ) ) ;
result . set ( feature_tag . tag ( ) , IntegerOrCalculated { feature_tag . value ( ) - > as_calculated ( ) } ) ;
2024-10-01 09:37:43 +01:00
}
}
return result ;
}
return { } ;
}
2024-12-20 11:32:17 +01:00
Optional < HashMap < FlyString , NumberOrCalculated > > ComputedProperties : : font_variation_settings ( ) const
2024-10-01 09:20:06 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : FontVariationSettings ) ;
2024-10-01 09:20:06 +01:00
2024-11-03 13:20:04 +01:00
if ( value . is_keyword ( ) )
2024-10-01 09:20:06 +01:00
return { } ; // normal
2024-11-03 13:20:04 +01:00
if ( value . is_value_list ( ) ) {
auto const & axis_tags = value . as_value_list ( ) . values ( ) ;
2024-10-01 09:20:06 +01:00
HashMap < FlyString , NumberOrCalculated > result ;
result . ensure_capacity ( axis_tags . size ( ) ) ;
for ( auto const & tag_value : axis_tags ) {
auto const & axis_tag = tag_value - > as_open_type_tagged ( ) ;
if ( axis_tag . value ( ) - > is_number ( ) ) {
result . set ( axis_tag . tag ( ) , axis_tag . value ( ) - > as_number ( ) . value ( ) ) ;
} else {
2024-12-11 15:05:56 +00:00
VERIFY ( axis_tag . value ( ) - > is_calculated ( ) ) ;
result . set ( axis_tag . tag ( ) , NumberOrCalculated { axis_tag . value ( ) - > as_calculated ( ) } ) ;
2024-10-01 09:20:06 +01:00
}
}
return result ;
}
return { } ;
}
2025-02-05 12:57:41 +00:00
GridTrackSizeList ComputedProperties : : grid_auto_columns ( ) const
2023-05-21 18:08:41 +03:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : GridAutoColumns ) ;
2024-11-03 13:20:04 +01:00
return value . as_grid_track_size_list ( ) . grid_track_size_list ( ) ;
2023-05-21 18:08:41 +03:00
}
2025-02-05 12:57:41 +00:00
GridTrackSizeList ComputedProperties : : grid_auto_rows ( ) const
2023-05-21 18:08:41 +03:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : GridAutoRows ) ;
2024-11-03 13:20:04 +01:00
return value . as_grid_track_size_list ( ) . grid_track_size_list ( ) ;
2023-05-21 18:08:41 +03:00
}
2025-02-05 12:57:41 +00:00
GridTrackSizeList ComputedProperties : : grid_template_columns ( ) const
2022-08-23 19:49:07 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : GridTemplateColumns ) ;
2024-11-03 13:20:04 +01:00
return value . as_grid_track_size_list ( ) . grid_track_size_list ( ) ;
2022-08-23 19:49:07 +02:00
}
2025-02-05 12:57:41 +00:00
GridTrackSizeList ComputedProperties : : grid_template_rows ( ) const
2022-08-23 19:49:07 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : GridTemplateRows ) ;
2024-11-03 13:20:04 +01:00
return value . as_grid_track_size_list ( ) . grid_track_size_list ( ) ;
2022-08-23 19:49:07 +02:00
}
2025-02-05 12:57:41 +00:00
GridAutoFlow ComputedProperties : : grid_auto_flow ( ) const
2023-08-17 20:25:18 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : GridAutoFlow ) ;
2024-11-03 13:20:04 +01:00
if ( ! value . is_grid_auto_flow ( ) )
2025-02-05 12:57:41 +00:00
return GridAutoFlow { } ;
2024-11-03 13:20:04 +01:00
auto & grid_auto_flow_value = value . as_grid_auto_flow ( ) ;
2025-02-05 12:57:41 +00:00
return GridAutoFlow { . row = grid_auto_flow_value . is_row ( ) , . dense = grid_auto_flow_value . is_dense ( ) } ;
2023-08-17 20:25:18 +02:00
}
2025-02-05 12:57:41 +00:00
GridTrackPlacement ComputedProperties : : grid_column_end ( ) const
2022-08-23 19:58:00 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : GridColumnEnd ) ;
2024-11-03 13:20:04 +01:00
return value . as_grid_track_placement ( ) . grid_track_placement ( ) ;
2022-08-23 19:58:00 +02:00
}
2025-02-05 12:57:41 +00:00
GridTrackPlacement ComputedProperties : : grid_column_start ( ) const
2022-08-23 19:58:00 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : GridColumnStart ) ;
2024-11-03 13:20:04 +01:00
return value . as_grid_track_placement ( ) . grid_track_placement ( ) ;
2022-08-23 19:58:00 +02:00
}
2025-02-05 12:57:41 +00:00
GridTrackPlacement ComputedProperties : : grid_row_end ( ) const
2022-08-23 19:58:00 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : GridRowEnd ) ;
2024-11-03 13:20:04 +01:00
return value . as_grid_track_placement ( ) . grid_track_placement ( ) ;
2022-08-23 19:58:00 +02:00
}
2025-02-05 12:57:41 +00:00
GridTrackPlacement ComputedProperties : : grid_row_start ( ) const
2022-08-23 19:58:00 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : GridRowStart ) ;
2024-11-03 13:20:04 +01:00
return value . as_grid_track_placement ( ) . grid_track_placement ( ) ;
2022-08-23 19:58:00 +02:00
}
2025-02-05 12:55:02 +00:00
BorderCollapse ComputedProperties : : border_collapse ( ) const
2023-01-02 23:01:29 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : BorderCollapse ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_border_collapse ( value . to_keyword ( ) ) . release_value ( ) ;
2023-01-02 23:01:29 +01:00
}
2024-12-20 11:32:17 +01:00
Vector < Vector < String > > ComputedProperties : : grid_template_areas ( ) const
2023-01-16 18:17:05 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : GridTemplateAreas ) ;
2024-11-03 13:20:04 +01:00
return value . as_grid_template_area ( ) . grid_template_area ( ) ;
2023-01-16 18:17:05 +01:00
}
2025-02-05 12:55:02 +00:00
ObjectFit ComputedProperties : : object_fit ( ) const
2023-08-01 20:06:50 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : ObjectFit ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_object_fit ( value . to_keyword ( ) ) . release_value ( ) ;
2023-08-01 20:06:50 +02:00
}
2025-02-05 12:57:41 +00:00
ObjectPosition ComputedProperties : : object_position ( ) const
2023-10-16 13:52:51 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : ObjectPosition ) ;
2024-11-03 13:20:04 +01:00
auto const & position = value . as_position ( ) ;
2025-02-05 12:57:41 +00:00
ObjectPosition object_position ;
2024-02-26 11:33:54 +01:00
auto const & edge_x = position . edge_x ( ) ;
auto const & edge_y = position . edge_y ( ) ;
if ( edge_x - > is_edge ( ) ) {
auto const & edge = edge_x - > as_edge ( ) ;
2024-11-29 22:44:14 +11:00
object_position . edge_x = edge . edge ( ) . value_or ( PositionEdge : : Left ) ;
2024-02-26 11:33:54 +01:00
object_position . offset_x = edge . offset ( ) ;
}
if ( edge_y - > is_edge ( ) ) {
auto const & edge = edge_y - > as_edge ( ) ;
2024-11-29 22:44:14 +11:00
object_position . edge_y = edge . edge ( ) . value_or ( PositionEdge : : Top ) ;
2024-02-26 11:33:54 +01:00
object_position . offset_y = edge . offset ( ) ;
}
return object_position ;
2023-10-16 13:52:51 +02:00
}
2025-02-05 12:55:02 +00:00
TableLayout ComputedProperties : : table_layout ( ) const
2023-08-07 01:32:52 +00:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : TableLayout ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_table_layout ( value . to_keyword ( ) ) . release_value ( ) ;
2023-08-07 01:32:52 +00:00
}
2025-02-05 12:55:02 +00:00
Direction ComputedProperties : : direction ( ) const
2024-08-10 23:13:26 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : Direction ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_direction ( value . to_keyword ( ) ) . release_value ( ) ;
2024-08-10 23:13:26 +01:00
}
2025-02-05 12:55:02 +00:00
UnicodeBidi ComputedProperties : : unicode_bidi ( ) const
2024-10-03 21:09:29 +02:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : UnicodeBidi ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_unicode_bidi ( value . to_keyword ( ) ) . release_value ( ) ;
2024-10-03 21:09:29 +02:00
}
2025-02-05 12:55:02 +00:00
WritingMode ComputedProperties : : writing_mode ( ) const
2024-10-27 22:12:54 +00:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : WritingMode ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_writing_mode ( value . to_keyword ( ) ) . release_value ( ) ;
2024-10-27 22:12:54 +00:00
}
2025-02-05 12:55:02 +00:00
UserSelect ComputedProperties : : user_select ( ) const
2025-01-08 01:51:29 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : UserSelect ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_user_select ( value . to_keyword ( ) ) . release_value ( ) ;
2025-01-08 01:51:29 +01:00
}
2025-02-05 12:55:02 +00:00
Isolation ComputedProperties : : isolation ( ) const
2025-01-11 01:34:47 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : Isolation ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_isolation ( value . to_keyword ( ) ) . release_value ( ) ;
2025-01-11 01:34:47 +01:00
}
2025-02-05 12:57:41 +00:00
Containment ComputedProperties : : contain ( ) const
2025-01-18 20:39:26 +01:00
{
2025-02-05 12:57:41 +00:00
Containment containment = { } ;
auto const & value = property ( PropertyID : : Contain ) ;
2025-01-18 20:39:26 +01:00
switch ( value . to_keyword ( ) ) {
case Keyword : : None :
// This value indicates that the property has no effect. The element renders as normal, with no containment effects applied.
return { } ;
case Keyword : : Strict :
// This value computes to 'size layout paint style', and thus turns on all forms of containment for the element.
containment . size_containment = true ;
containment . layout_containment = true ;
containment . paint_containment = true ;
containment . style_containment = true ;
break ;
case Keyword : : Content :
// This value computes to 'layout paint style', and thus turns on all forms of containment except size containment for the element.
containment . layout_containment = true ;
containment . paint_containment = true ;
containment . style_containment = true ;
break ;
case Keyword : : Size :
containment . size_containment = true ;
break ;
case Keyword : : InlineSize :
containment . inline_size_containment = true ;
break ;
case Keyword : : Layout :
containment . layout_containment = true ;
break ;
case Keyword : : Style :
containment . style_containment = true ;
break ;
case Keyword : : Paint :
containment . paint_containment = true ;
break ;
default :
if ( value . is_value_list ( ) ) {
auto & values = value . as_value_list ( ) . values ( ) ;
for ( auto const & item : values ) {
switch ( item - > to_keyword ( ) ) {
case Keyword : : Size :
containment . size_containment = true ;
break ;
case Keyword : : InlineSize :
containment . inline_size_containment = true ;
break ;
case Keyword : : Layout :
containment . layout_containment = true ;
break ;
case Keyword : : Style :
containment . style_containment = true ;
break ;
case Keyword : : Paint :
containment . paint_containment = true ;
break ;
default :
dbgln ( " `{}` is not supported in `contain` (yet?) " , item - > to_string ( CSSStyleValue : : SerializationMode : : Normal ) ) ;
break ;
}
}
}
}
return containment ;
}
2025-02-05 12:55:02 +00:00
MixBlendMode ComputedProperties : : mix_blend_mode ( ) const
2025-01-22 09:50:49 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : MixBlendMode ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_mix_blend_mode ( value . to_keyword ( ) ) . release_value ( ) ;
2025-01-22 09:50:49 +01:00
}
2025-02-21 17:56:24 +01:00
Optional < FlyString > ComputedProperties : : view_transition_name ( ) const
{
auto const & value = property ( PropertyID : : ViewTransitionName ) ;
2025-02-25 11:47:36 +00:00
if ( value . is_custom_ident ( ) )
return value . as_custom_ident ( ) . custom_ident ( ) ;
2025-02-21 17:56:24 +01:00
return { } ;
}
2025-02-05 12:55:02 +00:00
MaskType ComputedProperties : : mask_type ( ) const
2023-10-08 11:06:34 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : MaskType ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_mask_type ( value . to_keyword ( ) ) . release_value ( ) ;
2023-10-08 11:06:34 +01:00
}
2024-12-20 11:32:17 +01:00
Color ComputedProperties : : stop_color ( ) const
2023-04-19 18:51:00 +01:00
{
2025-02-05 12:57:41 +00:00
NonnullRawPtr < CSSStyleValue const > value = property ( PropertyID : : StopColor ) ;
2024-08-14 11:46:56 +01:00
if ( value - > is_keyword ( ) ) {
2023-07-28 22:24:36 +01:00
// Workaround lack of layout node to resolve current color.
2024-11-03 13:20:04 +01:00
auto const & keyword = value - > as_keyword ( ) ;
2025-02-05 12:57:41 +00:00
if ( keyword . keyword ( ) = = Keyword : : Currentcolor )
value = property ( PropertyID : : Color ) ;
2023-07-28 22:24:36 +01:00
}
2023-04-19 18:51:00 +01:00
if ( value - > has_color ( ) ) {
// FIXME: This is used by the SVGStopElement, which does not participate in layout,
2023-07-28 22:24:36 +01:00
// so can't pass a layout node (so can't resolve some colors, e.g. palette ones)
2023-04-19 18:51:00 +01:00
return value - > to_color ( { } ) ;
}
return Color : : Black ;
}
2024-12-20 11:32:17 +01:00
void ComputedProperties : : set_math_depth ( int math_depth )
2023-09-07 15:29:54 +01:00
{
2024-12-20 16:35:12 +01:00
m_math_depth = math_depth ;
2023-09-07 15:29:54 +01:00
// Make our children inherit our computed value, not our specified value.
set_property ( PropertyID : : MathDepth , MathDepthStyleValue : : create_integer ( IntegerStyleValue : : create ( math_depth ) ) ) ;
}
2024-12-20 11:32:17 +01:00
QuotesData ComputedProperties : : quotes ( ) const
2023-09-12 11:34:26 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : Quotes ) ;
2024-11-03 13:20:04 +01:00
if ( value . is_keyword ( ) ) {
switch ( value . to_keyword ( ) ) {
2024-08-14 14:06:03 +01:00
case Keyword : : Auto :
2023-09-12 11:34:26 +01:00
return QuotesData { . type = QuotesData : : Type : : Auto } ;
2024-08-14 14:06:03 +01:00
case Keyword : : None :
2023-09-12 11:34:26 +01:00
return QuotesData { . type = QuotesData : : Type : : None } ;
default :
break ;
}
}
2024-11-03 13:20:04 +01:00
if ( value . is_value_list ( ) ) {
auto & value_list = value . as_value_list ( ) ;
2023-09-12 11:34:26 +01:00
QuotesData quotes_data { . type = QuotesData : : Type : : Specified } ;
VERIFY ( value_list . size ( ) % 2 = = 0 ) ;
for ( auto i = 0u ; i < value_list . size ( ) ; i + = 2 ) {
quotes_data . strings . empend (
value_list . value_at ( i , false ) - > as_string ( ) . string_value ( ) ,
value_list . value_at ( i + 1 , false ) - > as_string ( ) . string_value ( ) ) ;
}
return quotes_data ;
}
return InitialValues : : quotes ( ) ;
}
2024-12-20 11:32:17 +01:00
Vector < CounterData > ComputedProperties : : counter_data ( PropertyID property_id ) const
2024-07-24 15:47:11 +01:00
{
2024-11-03 13:20:04 +01:00
auto const & value = property ( property_id ) ;
2024-07-24 15:47:11 +01:00
2024-11-03 13:20:04 +01:00
if ( value . is_counter_definitions ( ) ) {
auto & counter_definitions = value . as_counter_definitions ( ) . counter_definitions ( ) ;
2024-07-24 15:47:11 +01:00
Vector < CounterData > result ;
for ( auto & counter : counter_definitions ) {
CounterData data {
. name = counter . name ,
. is_reversed = counter . is_reversed ,
. value = { } ,
} ;
if ( counter . value ) {
if ( counter . value - > is_integer ( ) ) {
data . value = AK : : clamp_to < i32 > ( counter . value - > as_integer ( ) . integer ( ) ) ;
2024-12-11 15:05:56 +00:00
} else if ( counter . value - > is_calculated ( ) ) {
LibWeb/CSS: Wrap calc()-resolution data in a struct
Initially I added this to the existing CalculationContext, but in
reality, we have some data at parse-time and different data at
resolve-time, so it made more sense to keep those separate.
Instead of needing a variety of methods for resolving a Foo, depending
on whether we have a Layout::Node available, or a percentage basis, or
a length resolution context... put those in a
CalculationResolutionContext, and just pass that one thing to these
methods. This also removes the need for separate resolve_*_percentage()
methods, because we can just pass the percentage basis in to the regular
resolve_foo() method.
This also corrects the issue that *any* calculation may need to resolve
lengths, but we previously only passed a length resolution context to
specific types in some situations. Now, they can all have one available,
though it's up to the caller to provide it.
2025-01-22 16:05:32 +00:00
auto maybe_int = counter . value - > as_calculated ( ) . resolve_integer ( { } ) ;
2024-07-24 15:47:11 +01:00
if ( maybe_int . has_value ( ) )
data . value = AK : : clamp_to < i32 > ( * maybe_int ) ;
} else {
2024-12-07 00:59:49 +01:00
dbgln ( " Unimplemented type for {} integer value: '{}' " , string_from_property_id ( property_id ) , counter . value - > to_string ( CSSStyleValue : : SerializationMode : : Normal ) ) ;
2024-07-24 15:47:11 +01:00
}
}
result . append ( move ( data ) ) ;
}
return result ;
}
2024-11-03 13:20:04 +01:00
if ( value . to_keyword ( ) = = Keyword : : None )
2024-07-24 15:47:11 +01:00
return { } ;
2024-12-07 00:59:49 +01:00
dbgln ( " Unhandled type for {} value: '{}' " , string_from_property_id ( property_id ) , value . to_string ( CSSStyleValue : : SerializationMode : : Normal ) ) ;
2024-07-24 15:47:11 +01:00
return { } ;
}
2025-02-05 12:55:02 +00:00
ScrollbarWidth ComputedProperties : : scrollbar_width ( ) const
2024-02-27 09:37:18 +01:00
{
2025-02-05 12:57:41 +00:00
auto const & value = property ( PropertyID : : ScrollbarWidth ) ;
2025-02-05 12:55:02 +00:00
return keyword_to_scrollbar_width ( value . to_keyword ( ) ) . release_value ( ) ;
2024-02-27 09:37:18 +01:00
}
2020-03-07 10:27:02 +01:00
}