2020-01-18 09:38:21 +01:00
/*
2024-10-04 13:19:50 +02:00
* Copyright ( c ) 2018 - 2023 , Andreas Kling < andreas @ ladybird . org >
2023-06-08 15:25:16 +01:00
* Copyright ( c ) 2021 - 2023 , Sam Atkins < atkinssj @ serenityos . org >
2025-01-15 16:37:30 +01:00
* Copyright ( c ) 2025 , Jelle Raaijmakers < jelle @ 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
*/
2021-01-01 16:42:44 +01:00
# include <AK/Demangle.h>
2025-02-18 09:19:56 +01:00
# include <LibWeb/CSS/ComputedProperties.h>
2023-03-24 16:42:50 +00:00
# include <LibWeb/CSS/StyleValues/AbstractImageStyleValue.h>
2023-03-23 17:44:13 +00:00
# include <LibWeb/CSS/StyleValues/BackgroundRepeatStyleValue.h>
2023-03-23 17:54:05 +00:00
# include <LibWeb/CSS/StyleValues/BackgroundSizeStyleValue.h>
2023-03-25 00:33:20 +00:00
# include <LibWeb/CSS/StyleValues/BorderRadiusStyleValue.h>
2024-08-14 11:46:56 +01:00
# include <LibWeb/CSS/StyleValues/CSSKeywordValue.h>
2023-09-06 18:30:57 +02:00
# include <LibWeb/CSS/StyleValues/IntegerStyleValue.h>
2023-05-27 12:28:25 +01:00
# include <LibWeb/CSS/StyleValues/LengthStyleValue.h>
2023-06-01 16:16:15 +01:00
# include <LibWeb/CSS/StyleValues/NumberStyleValue.h>
2023-05-21 09:50:56 +02:00
# include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
2023-06-08 15:25:16 +01:00
# include <LibWeb/CSS/StyleValues/RatioStyleValue.h>
2023-03-25 00:12:21 +00:00
# include <LibWeb/CSS/StyleValues/StyleValueList.h>
2023-05-27 22:05:48 +02:00
# include <LibWeb/CSS/StyleValues/TimeStyleValue.h>
2023-04-23 01:31:17 +01:00
# include <LibWeb/CSS/StyleValues/URLStyleValue.h>
2020-03-07 10:32:51 +01:00
# include <LibWeb/DOM/Document.h>
2020-11-26 21:18:34 +01:00
# include <LibWeb/Dump.h>
2025-01-08 01:51:29 +01:00
# include <LibWeb/HTML/FormAssociatedElement.h>
2020-12-05 20:10:02 +01:00
# include <LibWeb/HTML/HTMLHtmlElement.h>
2021-10-06 20:02:41 +02:00
# include <LibWeb/Layout/BlockContainer.h>
2020-12-05 20:10:39 +01:00
# include <LibWeb/Layout/FormattingContext.h>
2020-11-22 15:53:01 +01:00
# include <LibWeb/Layout/Node.h>
2023-06-22 12:22:29 +00:00
# include <LibWeb/Layout/TableWrapper.h>
2021-01-01 18:55:47 +01:00
# include <LibWeb/Layout/TextNode.h>
2023-02-25 11:04:29 +01:00
# include <LibWeb/Layout/Viewport.h>
2025-02-18 09:19:56 +01:00
# include <LibWeb/Page/Page.h>
2025-02-19 10:54:44 +01:00
# include <LibWeb/SVG/SVGForeignObjectElement.h>
2019-06-15 22:49:44 +02:00
2020-11-22 15:53:01 +01:00
namespace Web : : Layout {
2020-03-07 10:27:02 +01:00
2020-11-22 15:53:01 +01:00
Node : : Node ( DOM : : Document & document , DOM : : Node * node )
2022-10-17 14:41:50 +02:00
: m_dom_node ( node ? * node : document )
2022-10-16 16:42:39 +02:00
, m_anonymous ( node = = nullptr )
2019-06-15 22:49:44 +02:00
{
2022-10-16 16:42:39 +02:00
if ( node )
2022-10-17 14:41:50 +02:00
node - > set_layout_node ( { } , * this ) ;
2019-06-15 22:49:44 +02:00
}
2022-10-17 14:41:50 +02:00
Node : : ~ Node ( ) = default ;
void Node : : visit_edges ( Cell : : Visitor & visitor )
2019-06-15 22:49:44 +02:00
{
2022-10-17 14:41:50 +02:00
Base : : visit_edges ( visitor ) ;
visitor . visit ( m_dom_node ) ;
2024-10-14 16:07:56 +02:00
for ( auto const & paintable : m_paintable ) {
2024-11-15 04:01:23 +13:00
visitor . visit ( GC : : Ptr { & paintable } ) ;
2024-10-14 16:07:56 +02:00
}
2023-09-16 23:30:15 +02:00
visitor . visit ( m_pseudo_element_generator ) ;
2022-10-17 14:41:50 +02:00
TreeNode : : visit_edges ( visitor ) ;
2019-06-15 22:49:44 +02:00
}
2022-03-22 18:34:02 +01:00
// https://www.w3.org/TR/css-display-3/#out-of-flow
bool Node : : is_out_of_flow ( FormattingContext const & formatting_context ) const
{
// A layout node is out of flow if either:
// 1. It is floated (which requires that floating is not inhibited).
if ( ! formatting_context . inhibits_floating ( ) & & computed_values ( ) . float_ ( ) ! = CSS : : Float : : None )
return true ;
// 2. It is "absolutely positioned".
if ( is_absolutely_positioned ( ) )
return true ;
return false ;
}
2020-11-22 15:53:01 +01:00
bool Node : : can_contain_boxes_with_position_absolute ( ) const
2020-06-05 16:54:28 +02:00
{
2023-10-27 15:17:36 +02:00
if ( computed_values ( ) . position ( ) ! = CSS : : Positioning : : Static )
2023-02-24 02:51:08 +03:00
return true ;
2023-02-25 11:04:29 +01:00
if ( is < Viewport > ( * this ) )
2023-02-24 02:51:08 +03:00
return true ;
// https://w3c.github.io/csswg-drafts/css-transforms-1/#propdef-transform
// Any computed value other than none for the transform affects containing block and stacking context
if ( ! computed_values ( ) . transformations ( ) . is_empty ( ) )
return true ;
2024-11-22 16:42:20 +01:00
if ( computed_values ( ) . translate ( ) . has_value ( ) )
return true ;
2024-11-22 16:11:33 +01:00
if ( computed_values ( ) . rotate ( ) . has_value ( ) )
return true ;
2024-11-22 18:07:16 +01:00
if ( computed_values ( ) . scale ( ) . has_value ( ) )
return true ;
2023-02-24 02:51:08 +03:00
2025-01-18 20:39:26 +01:00
// https://drafts.csswg.org/css-contain-2/#containment-types
// 4. The layout containment box establishes an absolute positioning containing block and a fixed positioning
// containing block.
// 4. The paint containment box establishes an absolute positioning containing block and a fixed positioning
// containing block.
if ( dom_node ( ) & & dom_node ( ) - > is_element ( ) ) {
auto element = as < DOM : : Element > ( dom_node ( ) ) ;
if ( element - > has_layout_containment ( ) | | element - > has_paint_containment ( ) )
return true ;
}
2023-02-24 02:51:08 +03:00
return false ;
2020-06-05 16:54:28 +02:00
}
2023-01-23 14:59:51 +01:00
static Box const * nearest_ancestor_capable_of_forming_a_containing_block ( Node const & node )
{
for ( auto const * ancestor = node . parent ( ) ; ancestor ; ancestor = ancestor - > parent ( ) ) {
2023-01-23 15:03:45 +01:00
if ( ancestor - > is_block_container ( )
2023-01-23 15:19:32 +01:00
| | ancestor - > display ( ) . is_flex_inside ( )
2023-07-28 14:23:12 +02:00
| | ancestor - > display ( ) . is_grid_inside ( )
| | ancestor - > is_svg_svg_box ( ) ) {
2025-01-21 09:12:05 -05:00
return as < Box > ( ancestor ) ;
2023-01-23 15:03:45 +01:00
}
2023-01-23 14:59:51 +01:00
}
return nullptr ;
}
Box const * Node : : containing_block ( ) const
2019-07-01 07:28:37 +02:00
{
2021-01-01 18:55:47 +01:00
if ( is < TextNode > ( * this ) )
2023-01-23 14:59:51 +01:00
return nearest_ancestor_capable_of_forming_a_containing_block ( * this ) ;
2020-06-05 16:54:28 +02:00
2021-01-06 11:07:02 +01:00
auto position = computed_values ( ) . position ( ) ;
2020-06-12 14:19:03 +02:00
2023-01-23 14:59:51 +01:00
// https://drafts.csswg.org/css-position-3/#absolute-cb
2023-10-27 15:17:36 +02:00
if ( position = = CSS : : Positioning : : Absolute ) {
2023-01-23 14:59:51 +01:00
auto const * ancestor = parent ( ) ;
2020-06-05 16:54:28 +02:00
while ( ancestor & & ! ancestor - > can_contain_boxes_with_position_absolute ( ) )
ancestor = ancestor - > parent ( ) ;
2023-02-19 12:28:50 +01:00
return static_cast < Box const * > ( ancestor ) ;
2020-06-05 16:54:28 +02:00
}
2023-10-27 15:17:36 +02:00
if ( position = = CSS : : Positioning : : Fixed )
2020-06-05 16:54:28 +02:00
return & root ( ) ;
2023-01-23 14:59:51 +01:00
return nearest_ancestor_capable_of_forming_a_containing_block ( * this ) ;
2019-07-01 07:28:37 +02:00
}
2019-09-25 12:40:37 +03:00
2025-03-06 18:10:38 +05:00
// returns containing block this node would have had if its position was static
2024-04-11 21:54:37 +02:00
Box const * Node : : static_position_containing_block ( ) const
{
return nearest_ancestor_capable_of_forming_a_containing_block ( * this ) ;
}
2023-06-14 15:31:40 +02:00
Box const * Node : : non_anonymous_containing_block ( ) const
2023-05-24 06:57:38 +00:00
{
auto nearest_ancestor_box = containing_block ( ) ;
VERIFY ( nearest_ancestor_box ) ;
while ( nearest_ancestor_box - > is_anonymous ( ) ) {
nearest_ancestor_box = nearest_ancestor_box - > containing_block ( ) ;
VERIFY ( nearest_ancestor_box ) ;
}
return nearest_ancestor_box ;
}
2022-10-23 17:57:31 +02:00
// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context
2021-05-07 19:03:25 +03:00
bool Node : : establishes_stacking_context ( ) const
{
2022-10-23 17:57:31 +02:00
// NOTE: While MDN is not authoritative, there isn't a single convenient location
// in the CSS specifications where the rules for stacking contexts is described.
// That's why the "spec link" here points to MDN.
2021-05-07 19:03:25 +03:00
if ( ! has_style ( ) )
return false ;
2023-03-18 12:09:22 +01:00
2024-10-09 02:57:57 +02:00
if ( is_svg_box ( ) | | is_svg_svg_box ( ) )
return false ;
2023-03-18 12:09:22 +01:00
// We make a stacking context for the viewport. Painting and hit testing starts from here.
if ( is_viewport ( ) )
return true ;
// Root element of the document (<html>).
if ( is_root_element ( ) )
2021-05-07 19:03:25 +03:00
return true ;
2023-03-18 12:09:22 +01:00
2021-05-07 19:03:25 +03:00
auto position = computed_values ( ) . position ( ) ;
2022-10-23 17:57:31 +02:00
// Element with a position value absolute or relative and z-index value other than auto.
2023-10-27 15:17:36 +02:00
if ( position = = CSS : : Positioning : : Absolute | | position = = CSS : : Positioning : : Relative ) {
2022-10-23 17:57:31 +02:00
if ( computed_values ( ) . z_index ( ) . has_value ( ) ) {
return true ;
}
}
// Element with a position value fixed or sticky.
2023-10-27 15:17:36 +02:00
if ( position = = CSS : : Positioning : : Fixed | | position = = CSS : : Positioning : : Sticky )
2021-05-07 19:03:25 +03:00
return true ;
2022-10-23 17:57:31 +02:00
2022-03-18 01:19:03 +01:00
if ( ! computed_values ( ) . transformations ( ) . is_empty ( ) )
return true ;
2022-09-13 19:51:47 +02:00
2024-11-22 16:42:20 +01:00
if ( computed_values ( ) . translate ( ) . has_value ( ) )
return true ;
2024-11-22 16:11:33 +01:00
if ( computed_values ( ) . rotate ( ) . has_value ( ) )
return true ;
2024-11-22 18:07:16 +01:00
if ( computed_values ( ) . scale ( ) . has_value ( ) )
return true ;
2022-09-13 19:51:47 +02:00
// Element that is a child of a flex container, with z-index value other than auto.
2022-10-06 16:02:53 +02:00
if ( parent ( ) & & parent ( ) - > display ( ) . is_flex_inside ( ) & & computed_values ( ) . z_index ( ) . has_value ( ) )
2022-09-13 19:51:47 +02:00
return true ;
// Element that is a child of a grid container, with z-index value other than auto.
2022-10-06 16:02:53 +02:00
if ( parent ( ) & & parent ( ) - > display ( ) . is_grid_inside ( ) & & computed_values ( ) . z_index ( ) . has_value ( ) )
2022-09-13 19:51:47 +02:00
return true ;
2024-10-25 15:37:21 +02:00
// https://drafts.fxtf.org/filter-effects/#FilterProperty
2022-10-24 16:05:10 +01:00
// https://drafts.fxtf.org/filter-effects-2/#backdrop-filter-operation
2024-10-25 15:37:21 +02:00
// A computed value of other than none results in the creation of both a stacking context
// [CSS21] and a Containing Block for absolute and fixed position descendants, unless the
// element it applies to is a document root element in the current browsing context.
2022-10-24 16:05:10 +01:00
// Spec Note: This rule works in the same way as for the filter property.
2024-12-18 11:34:25 +01:00
if ( ! computed_values ( ) . backdrop_filter ( ) . is_empty ( ) | | ! computed_values ( ) . filter ( ) . is_empty ( ) )
2022-10-24 16:05:10 +01:00
return true ;
2023-09-03 19:44:00 +01:00
// Element with any of the following properties with value other than none:
// - transform
// - filter
// - backdrop-filter
// - perspective
// - clip-path
// - mask / mask-image / mask-border
2024-11-16 03:25:48 +03:00
if ( computed_values ( ) . mask ( ) . has_value ( ) | | computed_values ( ) . clip_path ( ) . has_value ( ) | | computed_values ( ) . mask_image ( ) )
2023-09-03 19:44:00 +01:00
return true ;
2025-01-11 01:34:47 +01:00
// https://drafts.fxtf.org/compositing/#propdef-isolation
// For CSS, setting isolation to isolate will turn the element into a stacking context.
if ( computed_values ( ) . isolation ( ) = = CSS : : Isolation : : Isolate )
return true ;
2025-01-18 20:39:26 +01:00
// https://drafts.csswg.org/css-contain-2/#containment-types
// 5. The layout containment box creates a stacking context.
// 3. The paint containment box creates a stacking context.
if ( dom_node ( ) & & dom_node ( ) - > is_element ( ) ) {
auto element = as < DOM : : Element > ( dom_node ( ) ) ;
if ( element - > has_layout_containment ( ) | | element - > has_paint_containment ( ) )
return true ;
}
2025-01-22 09:50:49 +01:00
// https://drafts.fxtf.org/compositing/#mix-blend-mode
// Applying a blendmode other than normal to the element must establish a new stacking context.
if ( computed_values ( ) . mix_blend_mode ( ) ! = CSS : : MixBlendMode : : Normal )
return true ;
2025-02-21 17:56:24 +01:00
// https://drafts.csswg.org/css-view-transitions-1/#named-and-transitioning
// Elements captured in a view transition during a view transition or whose view-transition-name computed value is
// not 'none' (at any time):
// - Form a stacking context.
if ( computed_values ( ) . view_transition_name ( ) . has_value ( ) )
return true ;
2021-10-19 15:27:40 +02:00
return computed_values ( ) . opacity ( ) < 1.0f ;
2021-05-07 19:03:25 +03:00
}
2024-11-15 04:01:23 +13:00
GC : : Ptr < HTML : : Navigable > Node : : navigable ( ) const
2023-08-22 16:00:42 +02:00
{
return document ( ) . navigable ( ) ;
}
2023-02-25 11:04:29 +01:00
Viewport const & Node : : root ( ) const
2019-11-04 19:37:52 +01:00
{
2021-02-23 20:42:32 +01:00
VERIFY ( document ( ) . layout_node ( ) ) ;
2019-11-04 19:37:52 +01:00
return * document ( ) . layout_node ( ) ;
}
2023-02-25 11:04:29 +01:00
Viewport & Node : : root ( )
2019-11-04 19:37:52 +01:00
{
2021-02-23 20:42:32 +01:00
VERIFY ( document ( ) . layout_node ( ) ) ;
2019-11-04 19:37:52 +01:00
return * document ( ) . layout_node ( ) ;
}
2020-11-22 15:53:01 +01:00
bool Node : : is_floating ( ) const
2020-06-26 15:08:42 +02:00
{
if ( ! has_style ( ) )
return false ;
2021-05-29 23:03:05 +02:00
// flex-items don't float.
if ( is_flex_item ( ) )
return false ;
2021-01-06 11:07:02 +01:00
return computed_values ( ) . float_ ( ) ! = CSS : : Float : : None ;
2020-06-26 15:08:42 +02:00
}
2020-12-06 19:54:23 +01:00
bool Node : : is_positioned ( ) const
{
2023-10-27 15:17:36 +02:00
return has_style ( ) & & computed_values ( ) . position ( ) ! = CSS : : Positioning : : Static ;
2020-12-06 19:54:23 +01:00
}
2020-11-22 15:53:01 +01:00
bool Node : : is_absolutely_positioned ( ) const
2020-06-05 16:54:28 +02:00
{
2020-06-15 12:57:43 +02:00
if ( ! has_style ( ) )
return false ;
2021-01-06 11:07:02 +01:00
auto position = computed_values ( ) . position ( ) ;
2023-10-27 15:17:36 +02:00
return position = = CSS : : Positioning : : Absolute | | position = = CSS : : Positioning : : Fixed ;
2020-06-12 14:19:03 +02:00
}
2020-11-22 15:53:01 +01:00
bool Node : : is_fixed_position ( ) const
2020-06-12 14:19:03 +02:00
{
2020-06-15 12:57:43 +02:00
if ( ! has_style ( ) )
return false ;
2021-01-06 11:07:02 +01:00
auto position = computed_values ( ) . position ( ) ;
2023-10-27 15:17:36 +02:00
return position = = CSS : : Positioning : : Fixed ;
2020-06-23 23:15:23 +02:00
}
2024-08-24 19:20:31 +02:00
bool Node : : is_sticky_position ( ) const
{
if ( ! has_style ( ) )
return false ;
auto position = computed_values ( ) . position ( ) ;
return position = = CSS : : Positioning : : Sticky ;
}
2024-12-20 16:35:12 +01:00
NodeWithStyle : : NodeWithStyle ( DOM : : Document & document , DOM : : Node * node , GC : : Ref < CSS : : ComputedProperties > computed_style )
2020-11-22 15:53:01 +01:00
: Node ( document , node )
2024-01-27 08:38:27 +01:00
, m_computed_values ( make < CSS : : ComputedValues > ( ) )
2020-06-23 23:15:23 +02:00
{
m_has_style = true ;
2024-10-26 17:42:27 +02:00
apply_style ( computed_style ) ;
2021-01-06 14:10:53 +01:00
}
2024-01-27 08:38:27 +01:00
NodeWithStyle : : NodeWithStyle ( DOM : : Document & document , DOM : : Node * node , NonnullOwnPtr < CSS : : ComputedValues > computed_values )
2021-01-06 14:10:53 +01:00
: Node ( document , node )
, m_computed_values ( move ( computed_values ) )
{
m_has_style = true ;
2020-06-24 14:17:05 +02:00
}
2023-09-28 00:26:02 +02:00
void NodeWithStyle : : visit_edges ( Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
2024-01-27 08:38:27 +01:00
for ( auto & layer : computed_values ( ) . background_layers ( ) ) {
2023-09-28 00:26:02 +02:00
if ( layer . background_image & & layer . background_image - > is_image ( ) )
layer . background_image - > as_image ( ) . visit_edges ( visitor ) ;
}
if ( m_list_style_image & & m_list_style_image - > is_image ( ) )
m_list_style_image - > as_image ( ) . visit_edges ( visitor ) ;
}
2023-07-30 16:15:38 +01:00
// https://www.w3.org/TR/css-values-4/#snap-a-length-as-a-border-width
static CSSPixels snap_a_length_as_a_border_width ( double device_pixels_per_css_pixel , CSSPixels length )
{
// 1. Assert: len is non-negative.
VERIFY ( length > = 0 ) ;
// 2. If len is an integer number of device pixels, do nothing.
auto device_pixels = length . to_double ( ) * device_pixels_per_css_pixel ;
if ( device_pixels = = trunc ( device_pixels ) )
return length ;
// 3. If len is greater than zero, but less than 1 device pixel, round len up to 1 device pixel.
if ( device_pixels > 0 & & device_pixels < 1 )
2023-08-26 15:57:31 +01:00
return CSSPixels : : nearest_value_for ( 1 / device_pixels_per_css_pixel ) ;
2023-07-30 16:15:38 +01:00
// 4. If len is greater than 1 device pixel, round it down to the nearest integer number of device pixels.
if ( device_pixels > 1 )
2023-08-26 15:57:31 +01:00
return CSSPixels : : nearest_value_for ( floor ( device_pixels ) / device_pixels_per_css_pixel ) ;
2023-07-30 16:15:38 +01:00
return length ;
}
2025-01-15 16:37:30 +01:00
void NodeWithStyle : : apply_style ( CSS : : ComputedProperties const & computed_style )
2020-06-24 14:17:05 +02:00
{
2024-01-27 08:38:27 +01:00
auto & computed_values = mutable_computed_values ( ) ;
2020-06-24 14:17:05 +02:00
2025-01-02 12:59:09 +11:00
// NOTE: color-scheme must be set first to ensure system colors can be resolved correctly.
auto preferred_color_scheme = document ( ) . page ( ) . preferred_color_scheme ( ) ;
// FIXME: We can't just check for Auto because page().preferred_color_scheme() returns garbage data after startup.
if ( preferred_color_scheme ! = CSS : : PreferredColorScheme : : Dark & & preferred_color_scheme ! = CSS : : PreferredColorScheme : : Light ) {
preferred_color_scheme = document ( ) . page ( ) . palette ( ) . is_dark ( ) ? CSS : : PreferredColorScheme : : Dark : CSS : : PreferredColorScheme : : Light ;
}
2025-01-04 09:59:57 +11:00
computed_values . set_color_scheme ( computed_style . color_scheme ( preferred_color_scheme , document ( ) . supported_color_schemes ( ) ) ) ;
2025-01-02 12:59:09 +11:00
// NOTE: color must be set second to ensure currentColor can be resolved in other properties (e.g. background-color).
2023-03-05 22:31:44 +00:00
computed_values . set_color ( computed_style . color_or_fallback ( CSS : : PropertyID : : Color , * this , CSS : : InitialValues : : color ( ) ) ) ;
2022-03-23 15:57:05 +01:00
// NOTE: We have to be careful that font-related properties get set in the right order.
// m_font is used by Length::to_px() when resolving sizes against this layout node.
// That's why it has to be set before everything else.
2024-01-12 15:38:00 +01:00
computed_values . set_font_list ( computed_style . computed_font_list ( ) ) ;
2024-11-03 13:20:04 +01:00
computed_values . set_font_size ( computed_style . property ( CSS : : PropertyID : : FontSize ) . as_length ( ) . length ( ) . to_px ( * this ) ) ;
computed_values . set_font_weight ( round_to < int > ( computed_style . property ( CSS : : PropertyID : : FontWeight ) . as_number ( ) . number ( ) ) ) ;
2024-01-12 15:34:13 +01:00
computed_values . set_line_height ( computed_style . line_height ( ) ) ;
2021-01-06 11:31:19 +01:00
2022-03-24 17:38:05 +01:00
computed_values . set_vertical_align ( computed_style . vertical_align ( ) ) ;
2022-02-26 01:34:07 +01:00
2021-11-12 12:11:01 +00:00
{
2024-11-03 13:20:04 +01:00
auto const & attachments = computed_style . property ( CSS : : PropertyID : : BackgroundAttachment ) ;
auto const & clips = computed_style . property ( CSS : : PropertyID : : BackgroundClip ) ;
auto const & images = computed_style . property ( CSS : : PropertyID : : BackgroundImage ) ;
auto const & origins = computed_style . property ( CSS : : PropertyID : : BackgroundOrigin ) ;
auto const & x_positions = computed_style . property ( CSS : : PropertyID : : BackgroundPositionX ) ;
auto const & y_positions = computed_style . property ( CSS : : PropertyID : : BackgroundPositionY ) ;
auto const & repeats = computed_style . property ( CSS : : PropertyID : : BackgroundRepeat ) ;
auto const & sizes = computed_style . property ( CSS : : PropertyID : : BackgroundSize ) ;
2025-03-29 23:44:25 +01:00
auto const & background_blend_modes = computed_style . property ( CSS : : PropertyID : : BackgroundBlendMode ) ;
2024-11-03 13:20:04 +01:00
auto count_layers = [ ] ( auto const & maybe_style_value ) - > size_t {
if ( maybe_style_value . is_value_list ( ) )
return maybe_style_value . as_value_list ( ) . size ( ) ;
2021-11-12 12:11:01 +00:00
else
return 1 ;
} ;
2024-11-03 13:20:04 +01:00
auto value_for_layer = [ ] ( auto const & style_value , size_t layer_index ) - > RefPtr < CSS : : CSSStyleValue const > {
if ( style_value . is_value_list ( ) )
return style_value . as_value_list ( ) . value_at ( layer_index , true ) ;
2021-11-12 12:11:01 +00:00
return style_value ;
} ;
size_t layer_count = 1 ;
layer_count = max ( layer_count , count_layers ( attachments ) ) ;
layer_count = max ( layer_count , count_layers ( clips ) ) ;
layer_count = max ( layer_count , count_layers ( images ) ) ;
layer_count = max ( layer_count , count_layers ( origins ) ) ;
2023-04-03 00:04:00 +01:00
layer_count = max ( layer_count , count_layers ( x_positions ) ) ;
layer_count = max ( layer_count , count_layers ( y_positions ) ) ;
2021-11-12 12:11:01 +00:00
layer_count = max ( layer_count , count_layers ( repeats ) ) ;
layer_count = max ( layer_count , count_layers ( sizes ) ) ;
Vector < CSS : : BackgroundLayerData > layers ;
layers . ensure_capacity ( layer_count ) ;
for ( size_t layer_index = 0 ; layer_index < layer_count ; layer_index + + ) {
CSS : : BackgroundLayerData layer ;
2022-07-12 00:28:19 +01:00
if ( auto image_value = value_for_layer ( images , layer_index ) ; image_value ) {
2022-07-31 01:11:59 +01:00
if ( image_value - > is_abstract_image ( ) ) {
layer . background_image = image_value - > as_abstract_image ( ) ;
2023-02-20 18:56:08 +01:00
const_cast < CSS : : AbstractImageStyleValue & > ( * layer . background_image ) . load_any_resources ( document ( ) ) ;
2022-07-12 00:28:19 +01:00
}
2021-11-12 12:11:01 +00:00
}
2024-08-14 11:46:56 +01:00
if ( auto attachment_value = value_for_layer ( attachments , layer_index ) ; attachment_value & & attachment_value - > is_keyword ( ) ) {
2024-08-14 14:06:03 +01:00
switch ( attachment_value - > to_keyword ( ) ) {
case CSS : : Keyword : : Fixed :
2021-11-12 16:30:21 +00:00
layer . attachment = CSS : : BackgroundAttachment : : Fixed ;
break ;
2024-08-14 14:06:03 +01:00
case CSS : : Keyword : : Local :
2021-11-12 16:30:21 +00:00
layer . attachment = CSS : : BackgroundAttachment : : Local ;
break ;
2024-08-14 14:06:03 +01:00
case CSS : : Keyword : : Scroll :
2021-11-12 16:30:21 +00:00
layer . attachment = CSS : : BackgroundAttachment : : Scroll ;
break ;
default :
break ;
}
}
2024-08-14 14:06:03 +01:00
auto as_box = [ ] ( auto keyword ) {
switch ( keyword ) {
case CSS : : Keyword : : BorderBox :
2021-11-12 16:30:21 +00:00
return CSS : : BackgroundBox : : BorderBox ;
2024-08-14 14:06:03 +01:00
case CSS : : Keyword : : ContentBox :
2021-11-12 16:30:21 +00:00
return CSS : : BackgroundBox : : ContentBox ;
2024-08-14 14:06:03 +01:00
case CSS : : Keyword : : PaddingBox :
2021-11-12 16:30:21 +00:00
return CSS : : BackgroundBox : : PaddingBox ;
2024-08-14 14:06:03 +01:00
case CSS : : Keyword : : Text :
2024-03-03 14:13:27 +01:00
return CSS : : BackgroundBox : : Text ;
2021-11-12 16:30:21 +00:00
default :
VERIFY_NOT_REACHED ( ) ;
}
} ;
2024-08-14 11:46:56 +01:00
if ( auto origin_value = value_for_layer ( origins , layer_index ) ; origin_value & & origin_value - > is_keyword ( ) ) {
2024-08-14 14:06:03 +01:00
layer . origin = as_box ( origin_value - > to_keyword ( ) ) ;
2021-11-12 16:30:21 +00:00
}
2024-08-14 11:46:56 +01:00
if ( auto clip_value = value_for_layer ( clips , layer_index ) ; clip_value & & clip_value - > is_keyword ( ) ) {
2024-08-14 14:06:03 +01:00
layer . clip = as_box ( clip_value - > to_keyword ( ) ) ;
2021-11-12 16:30:21 +00:00
}
2023-04-03 00:04:00 +01:00
if ( auto position_value = value_for_layer ( x_positions , layer_index ) ; position_value & & position_value - > is_edge ( ) ) {
auto & position = position_value - > as_edge ( ) ;
2024-11-29 22:44:14 +11:00
layer . position_edge_x = position . edge ( ) . value_or ( CSS : : PositionEdge : : Left ) ;
2023-04-03 00:04:00 +01:00
layer . position_offset_x = position . offset ( ) ;
2021-11-12 16:30:21 +00:00
}
2023-04-03 00:04:00 +01:00
if ( auto position_value = value_for_layer ( y_positions , layer_index ) ; position_value & & position_value - > is_edge ( ) ) {
auto & position = position_value - > as_edge ( ) ;
2024-11-29 22:44:14 +11:00
layer . position_edge_y = position . edge ( ) . value_or ( CSS : : PositionEdge : : Top ) ;
2023-04-03 00:04:00 +01:00
layer . position_offset_y = position . offset ( ) ;
} ;
2021-11-12 16:30:21 +00:00
if ( auto size_value = value_for_layer ( sizes , layer_index ) ; size_value ) {
if ( size_value - > is_background_size ( ) ) {
auto & size = size_value - > as_background_size ( ) ;
layer . size_type = CSS : : BackgroundSize : : LengthPercentage ;
layer . size_x = size . size_x ( ) ;
layer . size_y = size . size_y ( ) ;
2024-08-14 11:46:56 +01:00
} else if ( size_value - > is_keyword ( ) ) {
2024-08-14 14:06:03 +01:00
switch ( size_value - > to_keyword ( ) ) {
case CSS : : Keyword : : Contain :
2021-11-12 16:30:21 +00:00
layer . size_type = CSS : : BackgroundSize : : Contain ;
break ;
2024-08-14 14:06:03 +01:00
case CSS : : Keyword : : Cover :
2021-11-12 16:30:21 +00:00
layer . size_type = CSS : : BackgroundSize : : Cover ;
break ;
default :
break ;
}
}
}
2021-11-12 12:11:01 +00:00
if ( auto repeat_value = value_for_layer ( repeats , layer_index ) ; repeat_value & & repeat_value - > is_background_repeat ( ) ) {
layer . repeat_x = repeat_value - > as_background_repeat ( ) . repeat_x ( ) ;
layer . repeat_y = repeat_value - > as_background_repeat ( ) . repeat_y ( ) ;
}
2025-03-29 23:44:25 +01:00
layer . blend_mode = CSS : : keyword_to_mix_blend_mode ( value_for_layer ( background_blend_modes , layer_index ) - > to_keyword ( ) ) . value_or ( CSS : : MixBlendMode : : Normal ) ;
2021-11-12 12:11:01 +00:00
layers . append ( move ( layer ) ) ;
}
computed_values . set_background_layers ( move ( layers ) ) ;
}
2022-03-24 17:38:05 +01:00
computed_values . set_background_color ( computed_style . color_or_fallback ( CSS : : PropertyID : : BackgroundColor , * this , CSS : : InitialValues : : background_color ( ) ) ) ;
2021-11-12 12:11:01 +00:00
2025-02-05 12:55:02 +00:00
computed_values . set_box_sizing ( computed_style . box_sizing ( ) ) ;
2021-10-05 16:55:02 +01:00
2024-09-27 17:11:05 +01:00
if ( auto maybe_font_language_override = computed_style . font_language_override ( ) ; maybe_font_language_override . has_value ( ) )
computed_values . set_font_language_override ( maybe_font_language_override . release_value ( ) ) ;
2024-10-01 09:37:43 +01:00
if ( auto maybe_font_feature_settings = computed_style . font_feature_settings ( ) ; maybe_font_feature_settings . has_value ( ) )
computed_values . set_font_feature_settings ( maybe_font_feature_settings . release_value ( ) ) ;
2024-12-05 01:21:45 +01:00
if ( auto maybe_font_variant_alternates = computed_style . font_variant_alternates ( ) ; maybe_font_variant_alternates . has_value ( ) )
computed_values . set_font_variant_alternates ( maybe_font_variant_alternates . release_value ( ) ) ;
2025-02-05 12:55:02 +00:00
computed_values . set_font_variant_caps ( computed_style . font_variant_caps ( ) ) ;
2024-12-05 01:21:45 +01:00
if ( auto maybe_font_variant_east_asian = computed_style . font_variant_east_asian ( ) ; maybe_font_variant_east_asian . has_value ( ) )
computed_values . set_font_variant_east_asian ( maybe_font_variant_east_asian . release_value ( ) ) ;
2025-02-05 12:55:02 +00:00
computed_values . set_font_variant_emoji ( computed_style . font_variant_emoji ( ) ) ;
2024-12-05 01:21:45 +01:00
if ( auto maybe_font_variant_ligatures = computed_style . font_variant_ligatures ( ) ; maybe_font_variant_ligatures . has_value ( ) )
computed_values . set_font_variant_ligatures ( maybe_font_variant_ligatures . release_value ( ) ) ;
if ( auto maybe_font_variant_numeric = computed_style . font_variant_numeric ( ) ; maybe_font_variant_numeric . has_value ( ) )
computed_values . set_font_variant_numeric ( maybe_font_variant_numeric . release_value ( ) ) ;
2025-02-05 12:55:02 +00:00
computed_values . set_font_variant_position ( computed_style . font_variant_position ( ) ) ;
2024-10-01 09:20:06 +01:00
if ( auto maybe_font_variation_settings = computed_style . font_variation_settings ( ) ; maybe_font_variation_settings . has_value ( ) )
computed_values . set_font_variation_settings ( maybe_font_variation_settings . release_value ( ) ) ;
2022-03-23 14:54:21 +01:00
2024-11-03 13:20:04 +01:00
auto const & border_bottom_left_radius = computed_style . property ( CSS : : PropertyID : : BorderBottomLeftRadius ) ;
if ( border_bottom_left_radius . is_border_radius ( ) ) {
2022-06-12 15:05:47 +01:00
computed_values . set_border_bottom_left_radius (
CSS : : BorderRadiusData {
2024-11-03 13:20:04 +01:00
border_bottom_left_radius . as_border_radius ( ) . horizontal_radius ( ) ,
border_bottom_left_radius . as_border_radius ( ) . vertical_radius ( ) } ) ;
2022-06-12 15:05:47 +01:00
}
2024-11-03 13:20:04 +01:00
auto const & border_bottom_right_radius = computed_style . property ( CSS : : PropertyID : : BorderBottomRightRadius ) ;
if ( border_bottom_right_radius . is_border_radius ( ) ) {
2022-06-12 15:05:47 +01:00
computed_values . set_border_bottom_right_radius (
CSS : : BorderRadiusData {
2024-11-03 13:20:04 +01:00
border_bottom_right_radius . as_border_radius ( ) . horizontal_radius ( ) ,
border_bottom_right_radius . as_border_radius ( ) . vertical_radius ( ) } ) ;
2022-06-12 15:05:47 +01:00
}
2024-11-03 13:20:04 +01:00
auto const & border_top_left_radius = computed_style . property ( CSS : : PropertyID : : BorderTopLeftRadius ) ;
if ( border_top_left_radius . is_border_radius ( ) ) {
2022-06-12 15:05:47 +01:00
computed_values . set_border_top_left_radius (
CSS : : BorderRadiusData {
2024-11-03 13:20:04 +01:00
border_top_left_radius . as_border_radius ( ) . horizontal_radius ( ) ,
border_top_left_radius . as_border_radius ( ) . vertical_radius ( ) } ) ;
2022-06-12 15:05:47 +01:00
}
2024-11-03 13:20:04 +01:00
auto const & border_top_right_radius = computed_style . property ( CSS : : PropertyID : : BorderTopRightRadius ) ;
if ( border_top_right_radius . is_border_radius ( ) ) {
2022-06-12 15:05:47 +01:00
computed_values . set_border_top_right_radius (
CSS : : BorderRadiusData {
2024-11-03 13:20:04 +01:00
border_top_right_radius . as_border_radius ( ) . horizontal_radius ( ) ,
border_top_right_radius . as_border_radius ( ) . vertical_radius ( ) } ) ;
2022-06-12 15:05:47 +01:00
}
2022-03-24 17:38:05 +01:00
computed_values . set_display ( computed_style . display ( ) ) ;
2021-01-07 14:41:50 +01:00
2025-02-05 12:55:02 +00:00
computed_values . set_flex_direction ( computed_style . flex_direction ( ) ) ;
computed_values . set_flex_wrap ( computed_style . flex_wrap ( ) ) ;
computed_values . set_flex_basis ( computed_style . flex_basis ( ) ) ;
2022-03-24 17:38:05 +01:00
computed_values . set_flex_grow ( computed_style . flex_grow ( ) ) ;
computed_values . set_flex_shrink ( computed_style . flex_shrink ( ) ) ;
2022-03-31 22:11:38 +02:00
computed_values . set_order ( computed_style . order ( ) ) ;
2022-07-31 18:47:09 +02:00
computed_values . set_clip ( computed_style . clip ( ) ) ;
2023-10-12 01:34:20 +02:00
2024-12-18 11:34:25 +01:00
auto resolve_filter = [ this ] ( CSS : : Filter const & computed_filter ) - > Vector < Gfx : : Filter > {
Vector < Gfx : : Filter > resolved_filter ;
2024-10-25 11:00:22 +02:00
for ( auto const & filter : computed_filter . filters ( ) ) {
2023-10-12 01:34:20 +02:00
filter . visit (
2024-10-25 11:00:22 +02:00
[ & ] ( CSS : : FilterOperation : : Blur const & blur ) {
2024-12-18 11:34:25 +01:00
resolved_filter . append ( Gfx : : BlurFilter {
2023-10-12 01:34:20 +02:00
. radius = blur . resolved_radius ( * this ) } ) ;
} ,
2024-10-25 11:00:22 +02:00
[ & ] ( CSS : : FilterOperation : : DropShadow const & drop_shadow ) {
2025-01-22 15:00:13 +00:00
CSS : : CalculationResolutionContext context {
. length_resolution_context = CSS : : Length : : ResolutionContext : : for_layout_node ( * this ) ,
} ;
auto to_px = [ & ] ( CSS : : LengthOrCalculated const & length ) {
return static_cast < float > ( length . resolved ( context ) . map ( [ & ] ( auto & it ) { return it . to_px ( * this ) . to_double ( ) ; } ) . value_or ( 0.0 ) ) ;
} ;
2023-10-12 01:34:20 +02:00
// The default value for omitted values is missing length values set to 0
// and the missing used color is taken from the color property.
2024-12-18 11:34:25 +01:00
resolved_filter . append ( Gfx : : DropShadowFilter {
2025-01-22 15:00:13 +00:00
. offset_x = to_px ( drop_shadow . offset_x ) ,
. offset_y = to_px ( drop_shadow . offset_y ) ,
. radius = drop_shadow . radius . has_value ( ) ? to_px ( * drop_shadow . radius ) : 0.0f ,
2023-10-12 01:34:20 +02:00
. color = drop_shadow . color . has_value ( ) ? * drop_shadow . color : this - > computed_values ( ) . color ( ) } ) ;
} ,
2024-10-25 11:00:22 +02:00
[ & ] ( CSS : : FilterOperation : : Color const & color_operation ) {
2024-12-18 11:34:25 +01:00
resolved_filter . append ( Gfx : : ColorFilter {
2024-10-25 11:00:22 +02:00
. type = color_operation . operation ,
2023-10-12 01:34:20 +02:00
. amount = color_operation . resolved_amount ( ) } ) ;
} ,
2024-10-25 11:00:22 +02:00
[ & ] ( CSS : : FilterOperation : : HueRotate const & hue_rotate ) {
2024-12-18 11:34:25 +01:00
resolved_filter . append ( Gfx : : HueRotateFilter { . angle_degrees = hue_rotate . angle_degrees ( * this ) } ) ;
2023-10-12 01:34:20 +02:00
} ) ;
}
2024-10-25 11:00:22 +02:00
return resolved_filter ;
} ;
if ( computed_style . backdrop_filter ( ) . has_filters ( ) )
computed_values . set_backdrop_filter ( resolve_filter ( computed_style . backdrop_filter ( ) ) ) ;
if ( computed_style . filter ( ) . has_filters ( ) )
computed_values . set_filter ( resolve_filter ( computed_style . filter ( ) ) ) ;
2021-05-30 20:22:25 +02:00
2025-02-05 12:55:02 +00:00
computed_values . set_justify_content ( computed_style . justify_content ( ) ) ;
computed_values . set_justify_items ( computed_style . justify_items ( ) ) ;
computed_values . set_justify_self ( computed_style . justify_self ( ) ) ;
2023-07-14 14:41:22 +02:00
2023-03-18 20:49:00 +01:00
auto accent_color = computed_style . accent_color ( * this ) ;
if ( accent_color . has_value ( ) )
computed_values . set_accent_color ( accent_color . value ( ) ) ;
2025-02-05 12:55:02 +00:00
computed_values . set_align_content ( computed_style . align_content ( ) ) ;
computed_values . set_align_items ( computed_style . align_items ( ) ) ;
computed_values . set_align_self ( computed_style . align_self ( ) ) ;
2022-10-14 13:50:06 +02:00
2025-02-05 12:55:02 +00:00
computed_values . set_appearance ( computed_style . appearance ( ) ) ;
2021-09-15 18:27:20 +02:00
2025-02-05 12:55:02 +00:00
computed_values . set_position ( computed_style . position ( ) ) ;
2022-07-11 23:52:36 +02:00
2025-02-05 12:55:02 +00:00
computed_values . set_text_align ( computed_style . text_align ( ) ) ;
computed_values . set_text_justify ( computed_style . text_justify ( ) ) ;
computed_values . set_text_overflow ( computed_style . text_overflow ( ) ) ;
2022-03-12 19:31:32 +00:00
2023-05-15 16:42:28 +02:00
if ( auto text_indent = computed_style . length_percentage ( CSS : : PropertyID : : TextIndent ) ; text_indent . has_value ( ) )
computed_values . set_text_indent ( text_indent . release_value ( ) ) ;
2025-02-05 12:55:02 +00:00
computed_values . set_tab_size ( computed_style . tab_size ( ) ) ;
2024-10-01 13:07:06 +01:00
2025-02-05 12:55:02 +00:00
computed_values . set_white_space ( computed_style . white_space ( ) ) ;
computed_values . set_word_break ( computed_style . word_break ( ) ) ;
if ( auto word_spacing = computed_style . word_spacing ( ) ; word_spacing . has_value ( ) )
2024-10-18 21:00:28 +01:00
computed_values . set_word_spacing ( word_spacing . value ( ) ) ;
2024-10-22 14:21:20 +01:00
auto letter_spacing = computed_style . letter_spacing ( ) ;
if ( letter_spacing . has_value ( ) )
computed_values . set_letter_spacing ( letter_spacing . value ( ) ) ;
2025-02-05 12:55:02 +00:00
computed_values . set_float ( computed_style . float_ ( ) ) ;
2020-06-26 15:08:42 +02:00
2024-10-09 13:36:09 +02:00
computed_values . set_border_spacing_horizontal ( computed_style . border_spacing_horizontal ( * this ) ) ;
computed_values . set_border_spacing_vertical ( computed_style . border_spacing_vertical ( * this ) ) ;
2023-06-16 02:35:03 +00:00
2025-02-05 12:55:02 +00:00
computed_values . set_caption_side ( computed_style . caption_side ( ) ) ;
computed_values . set_clear ( computed_style . clear ( ) ) ;
computed_values . set_overflow_x ( computed_style . overflow_x ( ) ) ;
computed_values . set_overflow_y ( computed_style . overflow_y ( ) ) ;
computed_values . set_content_visibility ( computed_style . content_visibility ( ) ) ;
computed_values . set_cursor ( computed_style . cursor ( ) ) ;
computed_values . set_image_rendering ( computed_style . image_rendering ( ) ) ;
computed_values . set_pointer_events ( computed_style . pointer_events ( ) ) ;
2022-04-14 16:22:35 +01:00
computed_values . set_text_decoration_line ( computed_style . text_decoration_line ( ) ) ;
2025-02-05 12:55:02 +00:00
computed_values . set_text_decoration_style ( computed_style . text_decoration_style ( ) ) ;
computed_values . set_text_transform ( computed_style . text_transform ( ) ) ;
2020-12-15 13:36:27 +01:00
2025-02-05 12:55:02 +00:00
computed_values . set_list_style_type ( computed_style . list_style_type ( ) ) ;
computed_values . set_list_style_position ( computed_style . list_style_position ( ) ) ;
2024-11-03 13:20:04 +01:00
auto const & list_style_image = computed_style . property ( CSS : : PropertyID : : ListStyleImage ) ;
if ( list_style_image . is_abstract_image ( ) ) {
m_list_style_image = list_style_image . as_abstract_image ( ) ;
2023-02-20 18:56:08 +01:00
const_cast < CSS : : AbstractImageStyleValue & > ( * m_list_style_image ) . load_any_resources ( document ( ) ) ;
2021-10-29 09:00:30 -04:00
}
2022-03-06 00:25:42 +01:00
// FIXME: The default text decoration color value is `currentcolor`, but since we can't resolve that easily,
// we just manually grab the value from `color`. This makes it dependent on `color` being
// specified first, so it's far from ideal.
2022-03-24 17:38:05 +01:00
computed_values . set_text_decoration_color ( computed_style . color_or_fallback ( CSS : : PropertyID : : TextDecorationColor , * this , computed_values . color ( ) ) ) ;
if ( auto maybe_text_decoration_thickness = computed_style . length_percentage ( CSS : : PropertyID : : TextDecorationThickness ) ; maybe_text_decoration_thickness . has_value ( ) )
2022-03-06 19:48:09 +01:00
computed_values . set_text_decoration_thickness ( maybe_text_decoration_thickness . release_value ( ) ) ;
2022-03-06 00:25:42 +01:00
2024-07-07 19:41:18 -06:00
computed_values . set_webkit_text_fill_color ( computed_style . color_or_fallback ( CSS : : PropertyID : : WebkitTextFillColor , * this , computed_values . color ( ) ) ) ;
2023-05-31 16:07:06 -04:00
computed_values . set_text_shadow ( computed_style . text_shadow ( * this ) ) ;
2022-03-23 21:16:36 +00:00
2022-03-24 17:38:05 +01:00
computed_values . set_z_index ( computed_style . z_index ( ) ) ;
computed_values . set_opacity ( computed_style . opacity ( ) ) ;
2022-03-21 15:42:57 +01:00
2025-02-05 12:55:02 +00:00
computed_values . set_visibility ( computed_style . visibility ( ) ) ;
2022-03-21 15:42:57 +01:00
2022-09-25 15:48:23 +02:00
computed_values . set_width ( computed_style . size_value ( CSS : : PropertyID : : Width ) ) ;
computed_values . set_min_width ( computed_style . size_value ( CSS : : PropertyID : : MinWidth ) ) ;
computed_values . set_max_width ( computed_style . size_value ( CSS : : PropertyID : : MaxWidth ) ) ;
computed_values . set_height ( computed_style . size_value ( CSS : : PropertyID : : Height ) ) ;
computed_values . set_min_height ( computed_style . size_value ( CSS : : PropertyID : : MinHeight ) ) ;
computed_values . set_max_height ( computed_style . size_value ( CSS : : PropertyID : : MaxHeight ) ) ;
2020-06-24 17:45:42 +02:00
2022-03-27 15:42:23 +02:00
computed_values . set_inset ( computed_style . length_box ( CSS : : PropertyID : : Left , CSS : : PropertyID : : Top , CSS : : PropertyID : : Right , CSS : : PropertyID : : Bottom , CSS : : Length : : make_auto ( ) ) ) ;
2022-03-24 17:38:05 +01:00
computed_values . set_margin ( computed_style . length_box ( CSS : : PropertyID : : MarginLeft , CSS : : PropertyID : : MarginTop , CSS : : PropertyID : : MarginRight , CSS : : PropertyID : : MarginBottom , CSS : : Length : : make_px ( 0 ) ) ) ;
computed_values . set_padding ( computed_style . length_box ( CSS : : PropertyID : : PaddingLeft , CSS : : PropertyID : : PaddingTop , CSS : : PropertyID : : PaddingRight , CSS : : PropertyID : : PaddingBottom , CSS : : Length : : make_px ( 0 ) ) ) ;
2020-06-24 19:41:12 +02:00
2023-05-31 16:07:06 -04:00
computed_values . set_box_shadow ( computed_style . box_shadow ( * this ) ) ;
2021-07-23 21:22:31 +02:00
2025-01-15 17:21:22 +00:00
if ( auto rotate_value = computed_style . rotate ( ) ; rotate_value . has_value ( ) )
2024-11-22 16:11:33 +01:00
computed_values . set_rotate ( rotate_value . release_value ( ) ) ;
2024-10-16 08:50:35 +02:00
2024-11-22 16:42:20 +01:00
if ( auto translate_value = computed_style . translate ( ) ; translate_value . has_value ( ) )
computed_values . set_translate ( translate_value . release_value ( ) ) ;
2024-11-22 18:07:16 +01:00
if ( auto scale_value = computed_style . scale ( ) ; scale_value . has_value ( ) )
computed_values . set_scale ( scale_value . release_value ( ) ) ;
2022-03-24 17:38:05 +01:00
computed_values . set_transformations ( computed_style . transformations ( ) ) ;
2025-02-05 12:55:02 +00:00
computed_values . set_transform_box ( computed_style . transform_box ( ) ) ;
2022-03-24 17:38:05 +01:00
computed_values . set_transform_origin ( computed_style . transform_origin ( ) ) ;
2021-09-18 17:20:00 +02:00
2024-11-03 13:20:04 +01:00
auto const & transition_delay_property = computed_style . property ( CSS : : PropertyID : : TransitionDelay ) ;
if ( transition_delay_property . is_time ( ) ) {
auto const & transition_delay = transition_delay_property . as_time ( ) ;
2023-05-27 22:05:48 +02:00
computed_values . set_transition_delay ( transition_delay . time ( ) ) ;
2024-12-11 15:05:56 +00:00
} else if ( transition_delay_property . is_calculated ( ) ) {
auto const & transition_delay = transition_delay_property . 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
computed_values . set_transition_delay ( transition_delay . resolve_time ( { . length_resolution_context = CSS : : Length : : ResolutionContext : : for_layout_node ( * this ) } ) . value ( ) ) ;
2023-05-27 22:05:48 +02:00
}
2025-04-04 23:56:09 +01:00
auto resolve_border_width = [ & ] ( CSS : : PropertyID width_property ) - > CSSPixels {
auto const & value = computed_style . property ( width_property ) ;
if ( value . is_calculated ( ) )
return max ( CSSPixels { 0 } ,
value . as_calculated ( ) . resolve_length ( { . length_resolution_context = CSS : : Length : : ResolutionContext : : for_layout_node ( * this ) } ) - > to_px ( * this ) ) ;
if ( value . is_length ( ) )
return value . as_length ( ) . length ( ) . to_px ( * this ) ;
if ( value . is_keyword ( ) ) {
// https://www.w3.org/TR/css-backgrounds-3/#valdef-line-width-thin
switch ( value . to_keyword ( ) ) {
case CSS : : Keyword : : Thin :
return 1 ;
case CSS : : Keyword : : Medium :
return 3 ;
case CSS : : Keyword : : Thick :
return 5 ;
default :
VERIFY_NOT_REACHED ( ) ;
}
}
VERIFY_NOT_REACHED ( ) ;
} ;
2021-01-06 10:34:31 +01:00
auto do_border_style = [ & ] ( CSS : : BorderData & border , CSS : : PropertyID width_property , CSS : : PropertyID color_property , CSS : : PropertyID style_property ) {
2021-09-17 20:04:35 +01:00
// FIXME: The default border color value is `currentcolor`, but since we can't resolve that easily,
// we just manually grab the value from `color`. This makes it dependent on `color` being
// specified first, so it's far from ideal.
2022-03-24 17:38:05 +01:00
border . color = computed_style . color_or_fallback ( color_property , * this , computed_values . color ( ) ) ;
2025-02-05 12:55:02 +00:00
border . line_style = computed_style . line_style ( style_property ) ;
2022-12-31 16:53:33 +00:00
// https://w3c.github.io/csswg-drafts/css-backgrounds/#border-style
// none
// No border. Color and width are ignored (i.e., the border has width 0). Note this means that the initial value of border-image-width will also resolve to zero.
// hidden
// Same as none, but has different behavior in the border conflict resolution rules for border-collapsed tables [CSS2].
if ( border . line_style = = CSS : : LineStyle : : None | | border . line_style = = CSS : : LineStyle : : Hidden ) {
2021-04-12 17:23:17 +03:00
border . width = 0 ;
2022-11-24 21:34:28 +01:00
} else {
2025-04-04 23:56:09 +01:00
border . width = snap_a_length_as_a_border_width ( document ( ) . page ( ) . client ( ) . device_pixels_per_css_pixel ( ) , resolve_border_width ( width_property ) ) ;
2022-11-24 21:34:28 +01:00
}
2020-12-04 16:11:55 +01:00
} ;
2021-01-06 10:34:31 +01:00
do_border_style ( computed_values . border_left ( ) , CSS : : PropertyID : : BorderLeftWidth , CSS : : PropertyID : : BorderLeftColor , CSS : : PropertyID : : BorderLeftStyle ) ;
do_border_style ( computed_values . border_top ( ) , CSS : : PropertyID : : BorderTopWidth , CSS : : PropertyID : : BorderTopColor , CSS : : PropertyID : : BorderTopStyle ) ;
do_border_style ( computed_values . border_right ( ) , CSS : : PropertyID : : BorderRightWidth , CSS : : PropertyID : : BorderRightColor , CSS : : PropertyID : : BorderRightStyle ) ;
do_border_style ( computed_values . border_bottom ( ) , CSS : : PropertyID : : BorderBottomWidth , CSS : : PropertyID : : BorderBottomColor , CSS : : PropertyID : : BorderBottomStyle ) ;
2021-09-16 12:28:14 +01:00
2024-11-03 13:20:04 +01:00
if ( auto const & outline_color = computed_style . property ( CSS : : PropertyID : : OutlineColor ) ; outline_color . has_color ( ) )
computed_values . set_outline_color ( outline_color . to_color ( * this ) ) ;
if ( auto const & outline_offset = computed_style . property ( CSS : : PropertyID : : OutlineOffset ) ; outline_offset . is_length ( ) )
computed_values . set_outline_offset ( outline_offset . as_length ( ) . length ( ) ) ;
2025-02-05 12:55:02 +00:00
computed_values . set_outline_style ( computed_style . outline_style ( ) ) ;
2025-04-04 23:56:09 +01:00
CSSPixels resolved_outline_width = 0 ;
if ( computed_values . outline_style ( ) ! = CSS : : OutlineStyle : : None )
resolved_outline_width = max ( CSSPixels { 0 } , resolve_border_width ( CSS : : PropertyID : : OutlineWidth ) ) ;
auto snapped_outline_width = snap_a_length_as_a_border_width ( document ( ) . page ( ) . client ( ) . device_pixels_per_css_pixel ( ) , resolved_outline_width ) ;
computed_values . set_outline_width ( CSS : : Length : : make_px ( snapped_outline_width ) ) ;
2023-08-02 17:24:14 +01:00
2023-05-22 10:25:07 +03:00
computed_values . set_grid_auto_columns ( computed_style . grid_auto_columns ( ) ) ;
computed_values . set_grid_auto_rows ( computed_style . grid_auto_rows ( ) ) ;
2022-08-23 19:49:07 +02:00
computed_values . set_grid_template_columns ( computed_style . grid_template_columns ( ) ) ;
computed_values . set_grid_template_rows ( computed_style . grid_template_rows ( ) ) ;
2022-08-23 19:58:00 +02:00
computed_values . set_grid_column_end ( computed_style . grid_column_end ( ) ) ;
computed_values . set_grid_column_start ( computed_style . grid_column_start ( ) ) ;
computed_values . set_grid_row_end ( computed_style . grid_row_end ( ) ) ;
computed_values . set_grid_row_start ( computed_style . grid_row_start ( ) ) ;
2023-01-16 18:17:05 +01:00
computed_values . set_grid_template_areas ( computed_style . grid_template_areas ( ) ) ;
2023-08-17 20:25:18 +02:00
computed_values . set_grid_auto_flow ( computed_style . grid_auto_flow ( ) ) ;
2022-02-24 16:52:58 +00:00
2024-03-03 20:24:11 +00:00
if ( auto cx_value = computed_style . length_percentage ( CSS : : PropertyID : : Cx ) ; cx_value . has_value ( ) )
computed_values . set_cx ( * cx_value ) ;
if ( auto cy_value = computed_style . length_percentage ( CSS : : PropertyID : : Cy ) ; cy_value . has_value ( ) )
computed_values . set_cy ( * cy_value ) ;
if ( auto r_value = computed_style . length_percentage ( CSS : : PropertyID : : R ) ; r_value . has_value ( ) )
computed_values . set_r ( * r_value ) ;
if ( auto rx_value = computed_style . length_percentage ( CSS : : PropertyID : : Rx ) ; rx_value . has_value ( ) )
computed_values . set_rx ( * rx_value ) ;
if ( auto ry_value = computed_style . length_percentage ( CSS : : PropertyID : : Ry ) ; ry_value . has_value ( ) )
computed_values . set_ry ( * ry_value ) ;
2024-01-28 17:48:59 +00:00
if ( auto x_value = computed_style . length_percentage ( CSS : : PropertyID : : X ) ; x_value . has_value ( ) )
computed_values . set_x ( * x_value ) ;
if ( auto y_value = computed_style . length_percentage ( CSS : : PropertyID : : Y ) ; y_value . has_value ( ) )
computed_values . set_y ( * y_value ) ;
2024-03-03 20:24:11 +00:00
2024-11-03 13:20:04 +01:00
auto const & fill = computed_style . property ( CSS : : PropertyID : : Fill ) ;
if ( fill . has_color ( ) )
computed_values . set_fill ( fill . to_color ( * this ) ) ;
else if ( fill . is_url ( ) )
computed_values . set_fill ( fill . as_url ( ) . url ( ) ) ;
auto const & stroke = computed_style . property ( CSS : : PropertyID : : Stroke ) ;
if ( stroke . has_color ( ) )
computed_values . set_stroke ( stroke . to_color ( * this ) ) ;
else if ( stroke . is_url ( ) )
computed_values . set_stroke ( stroke . as_url ( ) . url ( ) ) ;
if ( auto const & stop_color = computed_style . property ( CSS : : PropertyID : : StopColor ) ; stop_color . has_color ( ) )
computed_values . set_stop_color ( stop_color . to_color ( * this ) ) ;
auto const & stroke_width = computed_style . property ( CSS : : PropertyID : : StrokeWidth ) ;
2022-04-14 11:52:35 +01:00
// FIXME: Converting to pixels isn't really correct - values should be in "user units"
// https://svgwg.org/svg2-draft/coords.html#TermUserUnits
2024-11-03 13:20:04 +01:00
if ( stroke_width . is_number ( ) )
computed_values . set_stroke_width ( CSS : : Length : : make_px ( CSSPixels : : nearest_value_for ( stroke_width . as_number ( ) . number ( ) ) ) ) ;
else if ( stroke_width . is_length ( ) )
computed_values . set_stroke_width ( stroke_width . as_length ( ) . length ( ) ) ;
else if ( stroke_width . is_percentage ( ) )
computed_values . set_stroke_width ( CSS : : LengthPercentage { stroke_width . as_percentage ( ) . percentage ( ) } ) ;
2022-11-06 12:42:22 +01:00
2025-03-01 11:27:55 +01:00
auto const & mask_image = computed_style . property ( CSS : : PropertyID : : MaskImage ) ;
if ( mask_image . is_url ( ) ) {
computed_values . set_mask ( mask_image . as_url ( ) . url ( ) ) ;
} else if ( mask_image . is_abstract_image ( ) ) {
2024-11-16 03:25:48 +03:00
auto const & abstract_image = mask_image . as_abstract_image ( ) ;
computed_values . set_mask_image ( abstract_image ) ;
const_cast < CSS : : AbstractImageStyleValue & > ( abstract_image ) . load_any_resources ( document ( ) ) ;
}
2025-02-05 12:55:02 +00:00
computed_values . set_mask_type ( computed_style . mask_type ( ) ) ;
2023-10-08 11:06:34 +01:00
2024-11-03 13:20:04 +01:00
auto const & clip_path = computed_style . property ( CSS : : PropertyID : : ClipPath ) ;
if ( clip_path . is_url ( ) )
computed_values . set_clip_path ( clip_path . as_url ( ) . url ( ) ) ;
else if ( clip_path . is_basic_shape ( ) )
computed_values . set_clip_path ( clip_path . as_basic_shape ( ) ) ;
2025-02-05 12:55:02 +00:00
computed_values . set_clip_rule ( computed_style . clip_rule ( ) ) ;
computed_values . set_fill_rule ( computed_style . fill_rule ( ) ) ;
2023-06-11 16:43:46 +01:00
2023-05-19 20:35:39 +01:00
computed_values . set_fill_opacity ( computed_style . fill_opacity ( ) ) ;
2024-11-18 21:21:22 -05:00
2024-11-20 19:23:10 -05:00
if ( auto const & stroke_dasharray_or_none = computed_style . property ( CSS : : PropertyID : : StrokeDasharray ) ; ! stroke_dasharray_or_none . is_keyword ( ) ) {
auto const & stroke_dasharray = stroke_dasharray_or_none . as_value_list ( ) ;
Vector < Variant < CSS : : LengthPercentage , CSS : : NumberOrCalculated > > dashes ;
for ( auto const & value : stroke_dasharray . values ( ) ) {
if ( value - > is_length ( ) )
dashes . append ( CSS : : LengthPercentage { value - > as_length ( ) . length ( ) } ) ;
else if ( value - > is_percentage ( ) )
dashes . append ( CSS : : LengthPercentage { value - > as_percentage ( ) . percentage ( ) } ) ;
2024-12-11 15:05:56 +00:00
else if ( value - > is_calculated ( ) )
dashes . append ( CSS : : LengthPercentage { value - > as_calculated ( ) } ) ;
2024-11-20 19:23:10 -05:00
else if ( value - > is_number ( ) )
dashes . append ( CSS : : NumberOrCalculated { value - > as_number ( ) . number ( ) } ) ;
}
computed_values . set_stroke_dasharray ( move ( dashes ) ) ;
}
2024-11-18 21:21:22 -05:00
auto const & stroke_dashoffset = computed_style . property ( CSS : : PropertyID : : StrokeDashoffset ) ;
// FIXME: Converting to pixels isn't really correct - values should be in "user units"
// https://svgwg.org/svg2-draft/coords.html#TermUserUnits
if ( stroke_dashoffset . is_number ( ) )
computed_values . set_stroke_dashoffset ( CSS : : Length : : make_px ( CSSPixels : : nearest_value_for ( stroke_dashoffset . as_number ( ) . number ( ) ) ) ) ;
else if ( stroke_dashoffset . is_length ( ) )
computed_values . set_stroke_dashoffset ( stroke_dashoffset . as_length ( ) . length ( ) ) ;
else if ( stroke_dashoffset . is_percentage ( ) )
computed_values . set_stroke_dashoffset ( CSS : : LengthPercentage { stroke_dashoffset . as_percentage ( ) . percentage ( ) } ) ;
2025-02-05 12:55:02 +00:00
computed_values . set_stroke_linecap ( computed_style . stroke_linecap ( ) ) ;
computed_values . set_stroke_linejoin ( computed_style . stroke_linejoin ( ) ) ;
2024-10-28 20:51:16 -04:00
computed_values . set_stroke_miterlimit ( computed_style . stroke_miterlimit ( ) ) ;
2023-05-19 20:35:39 +01:00
computed_values . set_stroke_opacity ( computed_style . stroke_opacity ( ) ) ;
computed_values . set_stop_opacity ( computed_style . stop_opacity ( ) ) ;
2025-02-05 12:55:02 +00:00
computed_values . set_text_anchor ( computed_style . text_anchor ( ) ) ;
2023-07-19 19:12:00 +01:00
2024-11-03 13:20:04 +01:00
if ( auto const & column_count = computed_style . property ( CSS : : PropertyID : : ColumnCount ) ; column_count . is_integer ( ) )
computed_values . set_column_count ( CSS : : ColumnCount : : make_integer ( column_count . as_integer ( ) . integer ( ) ) ) ;
2023-09-06 18:30:57 +02:00
2025-02-05 12:55:02 +00:00
computed_values . set_column_span ( computed_style . column_span ( ) ) ;
2024-08-20 20:23:55 -04:00
2024-08-20 19:58:14 -04:00
computed_values . set_column_width ( computed_style . size_value ( CSS : : PropertyID : : ColumnWidth ) ) ;
2024-11-09 17:38:09 +01:00
computed_values . set_column_gap ( computed_style . gap_value ( CSS : : PropertyID : : ColumnGap ) ) ;
computed_values . set_row_gap ( computed_style . gap_value ( CSS : : PropertyID : : RowGap ) ) ;
2023-01-02 23:01:29 +01:00
2025-02-05 12:55:02 +00:00
computed_values . set_border_collapse ( computed_style . border_collapse ( ) ) ;
2023-06-08 15:25:16 +01:00
2025-02-05 12:55:02 +00:00
computed_values . set_table_layout ( computed_style . table_layout ( ) ) ;
2023-08-07 01:32:52 +00:00
2024-11-03 13:20:04 +01:00
auto const & aspect_ratio = computed_style . property ( CSS : : PropertyID : : AspectRatio ) ;
if ( aspect_ratio . is_value_list ( ) ) {
auto const & values_list = aspect_ratio . as_value_list ( ) . values ( ) ;
2023-06-08 15:25:16 +01:00
if ( values_list . size ( ) = = 2
2024-08-14 14:06:03 +01:00
& & values_list [ 0 ] - > is_keyword ( ) & & values_list [ 0 ] - > as_keyword ( ) . keyword ( ) = = CSS : : Keyword : : Auto
2023-06-08 15:25:16 +01:00
& & values_list [ 1 ] - > is_ratio ( ) ) {
computed_values . set_aspect_ratio ( { true , values_list [ 1 ] - > as_ratio ( ) . ratio ( ) } ) ;
}
2024-11-03 13:20:04 +01:00
} else if ( aspect_ratio . is_keyword ( ) & & aspect_ratio . as_keyword ( ) . keyword ( ) = = CSS : : Keyword : : Auto ) {
2023-06-08 15:25:16 +01:00
computed_values . set_aspect_ratio ( { true , { } } ) ;
2024-11-03 13:20:04 +01:00
} else if ( aspect_ratio . is_ratio ( ) ) {
2024-10-24 21:03:49 +02:00
// https://drafts.csswg.org/css-sizing-4/#aspect-ratio
// If the <ratio> is degenerate, the property instead behaves as auto.
2024-11-03 13:20:04 +01:00
if ( aspect_ratio . as_ratio ( ) . ratio ( ) . is_degenerate ( ) )
2024-10-24 21:03:49 +02:00
computed_values . set_aspect_ratio ( { true , { } } ) ;
else
2024-11-03 13:20:04 +01:00
computed_values . set_aspect_ratio ( { false , aspect_ratio . as_ratio ( ) . ratio ( ) } ) ;
2023-06-08 15:25:16 +01:00
}
2023-07-03 12:49:13 +02:00
2024-11-03 13:20:04 +01:00
auto const & math_shift_value = computed_style . property ( CSS : : PropertyID : : MathShift ) ;
if ( auto math_shift = keyword_to_math_shift ( math_shift_value . to_keyword ( ) ) ; math_shift . has_value ( ) )
2023-09-05 20:23:15 +01:00
computed_values . set_math_shift ( math_shift . value ( ) ) ;
2024-11-03 13:20:04 +01:00
auto const & math_style_value = computed_style . property ( CSS : : PropertyID : : MathStyle ) ;
if ( auto math_style = keyword_to_math_style ( math_style_value . to_keyword ( ) ) ; math_style . has_value ( ) )
2023-09-05 20:23:15 +01:00
computed_values . set_math_style ( math_style . value ( ) ) ;
2023-09-07 15:29:54 +01:00
computed_values . set_math_depth ( computed_style . math_depth ( ) ) ;
2023-09-12 11:34:26 +01:00
computed_values . set_quotes ( computed_style . quotes ( ) ) ;
2024-07-24 15:47:11 +01:00
computed_values . set_counter_increment ( computed_style . counter_data ( CSS : : PropertyID : : CounterIncrement ) ) ;
computed_values . set_counter_reset ( computed_style . counter_data ( CSS : : PropertyID : : CounterReset ) ) ;
computed_values . set_counter_set ( computed_style . counter_data ( CSS : : PropertyID : : CounterSet ) ) ;
2023-09-07 15:29:54 +01:00
2025-02-05 12:55:02 +00:00
computed_values . set_object_fit ( computed_style . object_fit ( ) ) ;
2024-02-26 11:33:54 +01:00
computed_values . set_object_position ( computed_style . object_position ( ) ) ;
2025-02-05 12:55:02 +00:00
computed_values . set_direction ( computed_style . direction ( ) ) ;
computed_values . set_unicode_bidi ( computed_style . unicode_bidi ( ) ) ;
computed_values . set_scrollbar_width ( computed_style . scrollbar_width ( ) ) ;
computed_values . set_writing_mode ( computed_style . writing_mode ( ) ) ;
computed_values . set_user_select ( computed_style . user_select ( ) ) ;
computed_values . set_isolation ( computed_style . isolation ( ) ) ;
computed_values . set_mix_blend_mode ( computed_style . mix_blend_mode ( ) ) ;
2025-02-21 17:56:24 +01:00
computed_values . set_view_transition_name ( computed_style . view_transition_name ( ) ) ;
2025-01-22 09:50:49 +01:00
2025-03-09 13:59:33 +00:00
computed_values . set_caret_color ( computed_style . caret_color ( * this ) ) ;
2024-01-07 13:05:20 +01:00
propagate_style_to_anonymous_wrappers ( ) ;
2025-01-15 16:37:30 +01:00
2025-02-04 23:05:00 +01:00
if ( auto * box_node = as_if < NodeWithStyleAndBoxModelMetrics > ( * this ) )
box_node - > propagate_style_along_continuation ( computed_style ) ;
2024-01-07 13:05:20 +01:00
}
void NodeWithStyle : : propagate_style_to_anonymous_wrappers ( )
{
// Update the style of any anonymous wrappers that inherit from this node.
2023-07-03 12:49:13 +02:00
// FIXME: This is pretty hackish. It would be nicer if they shared the inherited style
// data structure somehow, so this wasn't necessary.
2024-01-07 13:05:20 +01:00
// If this is a `display:table` box with an anonymous wrapper parent,
// the parent inherits style from *this* node, not the other way around.
if ( display ( ) . is_table_inside ( ) & & is < TableWrapper > ( parent ( ) ) ) {
auto & table_wrapper = * static_cast < TableWrapper * > ( parent ( ) ) ;
2024-01-27 08:38:27 +01:00
static_cast < CSS : : MutableComputedValues & > ( static_cast < CSS : : ComputedValues & > ( const_cast < CSS : : ImmutableComputedValues & > ( table_wrapper . computed_values ( ) ) ) ) . inherit_from ( computed_values ( ) ) ;
transfer_table_box_computed_values_to_wrapper_computed_values ( table_wrapper . mutable_computed_values ( ) ) ;
2024-01-07 13:05:20 +01:00
}
// Propagate style to all anonymous children (except table wrappers!)
for_each_child_of_type < NodeWithStyle > ( [ & ] ( NodeWithStyle & child ) {
if ( child . is_anonymous ( ) & & ! is < TableWrapper > ( child ) ) {
2023-07-03 12:49:13 +02:00
auto & child_computed_values = static_cast < CSS : : MutableComputedValues & > ( static_cast < CSS : : ComputedValues & > ( const_cast < CSS : : ImmutableComputedValues & > ( child . computed_values ( ) ) ) ) ;
2024-01-27 08:38:27 +01:00
child_computed_values . inherit_from ( computed_values ( ) ) ;
2023-07-03 12:49:13 +02:00
}
2024-05-04 14:59:52 +01:00
return IterationDecision : : Continue ;
2023-07-03 12:49:13 +02:00
} ) ;
2020-06-05 16:54:28 +02:00
}
2020-12-05 20:10:02 +01:00
bool Node : : is_root_element ( ) const
{
if ( is_anonymous ( ) )
return false ;
return is < HTML : : HTMLHtmlElement > ( * dom_node ( ) ) ;
}
2024-04-05 09:26:03 +02:00
String Node : : debug_description ( ) const
2022-02-19 16:39:32 +01:00
{
StringBuilder builder ;
2022-10-17 14:41:50 +02:00
builder . append ( class_name ( ) ) ;
2022-02-19 16:39:32 +01:00
if ( dom_node ( ) ) {
builder . appendff ( " <{}> " , dom_node ( ) - > node_name ( ) ) ;
if ( dom_node ( ) - > is_element ( ) ) {
auto & element = static_cast < DOM : : Element const & > ( * dom_node ( ) ) ;
2024-01-13 20:12:25 +13:00
if ( element . id ( ) . has_value ( ) )
builder . appendff ( " #{} " , element . id ( ) . value ( ) ) ;
2022-02-19 16:39:32 +01:00
for ( auto const & class_name : element . class_names ( ) )
builder . appendff ( " .{} " , class_name ) ;
}
} else {
2022-07-11 17:32:29 +00:00
builder . append ( " (anonymous) " sv ) ;
2022-02-19 16:39:32 +01:00
}
2024-04-05 09:26:03 +02:00
return MUST ( builder . to_string ( ) ) ;
2022-02-19 16:39:32 +01:00
}
2022-10-06 15:33:09 +02:00
CSS : : Display Node : : display ( ) const
{
if ( ! has_style ( ) ) {
// NOTE: No style means this is dumb text content.
2023-09-04 17:39:15 +01:00
return CSS : : Display ( CSS : : DisplayOutside : : Inline , CSS : : DisplayInside : : Flow ) ;
2022-10-06 15:33:09 +02:00
}
return computed_values ( ) . display ( ) ;
}
2022-10-06 14:39:11 +02:00
bool Node : : is_inline ( ) const
{
2022-10-06 16:02:53 +02:00
return display ( ) . is_inline_outside ( ) ;
2022-10-06 14:39:11 +02:00
}
2021-01-01 18:55:47 +01:00
bool Node : : is_inline_block ( ) const
{
2022-10-06 16:02:53 +02:00
auto display = this - > display ( ) ;
return display . is_inline_outside ( ) & & display . is_flow_root_inside ( ) ;
2021-01-01 18:55:47 +01:00
}
2021-01-06 14:10:53 +01:00
2023-01-16 13:51:49 +01:00
bool Node : : is_inline_table ( ) const
{
auto display = this - > display ( ) ;
return display . is_inline_outside ( ) & & display . is_table_inside ( ) ;
}
2024-11-15 04:01:23 +13:00
GC : : Ref < NodeWithStyle > NodeWithStyle : : create_anonymous_wrapper ( ) const
2021-01-06 14:10:53 +01:00
{
2024-11-14 06:13:46 +13:00
auto wrapper = heap ( ) . allocate < BlockContainer > ( const_cast < DOM : : Document & > ( document ( ) ) , nullptr , computed_values ( ) . clone_inherited_values ( ) ) ;
2024-01-27 08:38:27 +01:00
wrapper - > mutable_computed_values ( ) . set_display ( CSS : : Display ( CSS : : DisplayOutside : : Block , CSS : : DisplayInside : : Flow ) ) ;
2024-09-03 11:08:46 +02:00
// NOTE: These properties are not inherited, but we still have to propagate them to anonymous wrappers.
wrapper - > mutable_computed_values ( ) . set_text_decoration_line ( computed_values ( ) . text_decoration_line ( ) ) ;
wrapper - > mutable_computed_values ( ) . set_text_decoration_thickness ( computed_values ( ) . text_decoration_thickness ( ) ) ;
wrapper - > mutable_computed_values ( ) . set_text_decoration_color ( computed_values ( ) . text_decoration_color ( ) ) ;
wrapper - > mutable_computed_values ( ) . set_text_decoration_style ( computed_values ( ) . text_decoration_style ( ) ) ;
2022-10-17 14:41:50 +02:00
return * wrapper ;
2021-01-06 14:10:53 +01:00
}
2025-01-11 20:22:24 +01:00
void NodeWithStyle : : set_computed_values ( NonnullOwnPtr < CSS : : ComputedValues > computed_values )
{
m_computed_values = move ( computed_values ) ;
}
2023-01-09 08:27:39 +03:00
void NodeWithStyle : : reset_table_box_computed_values_used_by_wrapper_to_init_values ( )
{
2023-05-29 14:11:19 +03:00
VERIFY ( this - > display ( ) . is_table_inside ( ) ) ;
2023-01-09 08:27:39 +03:00
2024-01-27 08:38:27 +01:00
auto & mutable_computed_values = this - > mutable_computed_values ( ) ;
2023-06-22 18:11:28 +00:00
mutable_computed_values . set_position ( CSS : : InitialValues : : position ( ) ) ;
mutable_computed_values . set_float ( CSS : : InitialValues : : float_ ( ) ) ;
mutable_computed_values . set_clear ( CSS : : InitialValues : : clear ( ) ) ;
mutable_computed_values . set_inset ( CSS : : InitialValues : : inset ( ) ) ;
mutable_computed_values . set_margin ( CSS : : InitialValues : : margin ( ) ) ;
2025-02-15 16:58:35 +01:00
// AD-HOC:
// To match other browsers, z-index needs to be moved to the wrapper box as well,
// even if the spec does not mention that: https://github.com/w3c/csswg-drafts/issues/11689
// Note that there may be more properties that need to be added to this list.
mutable_computed_values . set_z_index ( CSS : : InitialValues : : z_index ( ) ) ;
2023-01-09 08:27:39 +03:00
}
2023-06-22 12:22:29 +00:00
void NodeWithStyle : : transfer_table_box_computed_values_to_wrapper_computed_values ( CSS : : ComputedValues & wrapper_computed_values )
{
// The computed values of properties 'position', 'float', 'margin-*', 'top', 'right', 'bottom', and 'left' on the table element are used on the table wrapper box and not the table box;
// all other values of non-inheritable properties are used on the table box and not the table wrapper box.
// (Where the table element's values are not used on the table and table wrapper boxes, the initial values are used instead.)
auto & mutable_wrapper_computed_values = static_cast < CSS : : MutableComputedValues & > ( wrapper_computed_values ) ;
if ( display ( ) . is_inline_outside ( ) )
mutable_wrapper_computed_values . set_display ( CSS : : Display : : from_short ( CSS : : Display : : Short : : InlineBlock ) ) ;
else
mutable_wrapper_computed_values . set_display ( CSS : : Display : : from_short ( CSS : : Display : : Short : : FlowRoot ) ) ;
mutable_wrapper_computed_values . set_position ( computed_values ( ) . position ( ) ) ;
mutable_wrapper_computed_values . set_inset ( computed_values ( ) . inset ( ) ) ;
mutable_wrapper_computed_values . set_float ( computed_values ( ) . float_ ( ) ) ;
mutable_wrapper_computed_values . set_clear ( computed_values ( ) . clear ( ) ) ;
mutable_wrapper_computed_values . set_margin ( computed_values ( ) . margin ( ) ) ;
2025-02-15 16:58:35 +01:00
// AD-HOC:
// To match other browsers, z-index needs to be moved to the wrapper box as well,
// even if the spec does not mention that: https://github.com/w3c/csswg-drafts/issues/11689
// Note that there may be more properties that need to be added to this list.
mutable_wrapper_computed_values . set_z_index ( computed_values ( ) . z_index ( ) ) ;
2023-06-22 12:22:29 +00:00
reset_table_box_computed_values_used_by_wrapper_to_init_values ( ) ;
}
2024-10-13 21:29:47 +02:00
bool NodeWithStyle : : is_body ( ) const
{
return dom_node ( ) & & dom_node ( ) = = document ( ) . body ( ) ;
}
static bool overflow_value_makes_box_a_scroll_container ( CSS : : Overflow overflow )
{
switch ( overflow ) {
case CSS : : Overflow : : Clip :
case CSS : : Overflow : : Visible :
return false ;
case CSS : : Overflow : : Auto :
case CSS : : Overflow : : Hidden :
case CSS : : Overflow : : Scroll :
return true ;
}
VERIFY_NOT_REACHED ( ) ;
}
bool NodeWithStyle : : is_scroll_container ( ) const
{
// NOTE: This isn't in the spec, but we want the viewport to behave like a scroll container.
if ( is_viewport ( ) )
return true ;
return overflow_value_makes_box_a_scroll_container ( computed_values ( ) . overflow_x ( ) )
| | overflow_value_makes_box_a_scroll_container ( computed_values ( ) . overflow_y ( ) ) ;
}
2024-11-15 04:01:23 +13:00
void Node : : add_paintable ( GC : : Ptr < Painting : : Paintable > paintable )
2024-10-14 16:07:56 +02:00
{
if ( ! paintable )
return ;
m_paintable . append ( * paintable ) ;
}
void Node : : clear_paintables ( )
2022-03-10 15:50:57 +01:00
{
2024-10-14 16:07:56 +02:00
m_paintable . clear ( ) ;
2022-03-10 15:50:57 +01:00
}
2024-11-15 04:01:23 +13:00
GC : : Ptr < Painting : : Paintable > Node : : create_paintable ( ) const
2022-03-10 15:50:57 +01:00
{
return nullptr ;
}
2022-08-28 13:42:07 +02:00
bool Node : : is_anonymous ( ) const
{
2022-10-16 16:42:39 +02:00
return m_anonymous ;
2022-08-28 13:42:07 +02:00
}
DOM : : Node const * Node : : dom_node ( ) const
{
2022-10-16 16:42:39 +02:00
if ( m_anonymous )
return nullptr ;
2022-08-28 13:42:07 +02:00
return m_dom_node . ptr ( ) ;
}
DOM : : Node * Node : : dom_node ( )
{
2022-10-16 16:42:39 +02:00
if ( m_anonymous )
return nullptr ;
2022-08-28 13:42:07 +02:00
return m_dom_node . ptr ( ) ;
}
2023-08-06 01:29:55 +02:00
DOM : : Element const * Node : : pseudo_element_generator ( ) const
{
2025-03-19 15:52:33 +00:00
VERIFY ( m_generated_for . has_value ( ) ) ;
2023-08-06 01:29:55 +02:00
return m_pseudo_element_generator . ptr ( ) ;
}
DOM : : Element * Node : : pseudo_element_generator ( )
{
2025-03-19 15:52:33 +00:00
VERIFY ( m_generated_for . has_value ( ) ) ;
2023-08-06 01:29:55 +02:00
return m_pseudo_element_generator . ptr ( ) ;
}
2022-08-28 13:42:07 +02:00
DOM : : Document & Node : : document ( )
{
2022-10-16 16:42:39 +02:00
return m_dom_node - > document ( ) ;
2022-08-28 13:42:07 +02:00
}
DOM : : Document const & Node : : document ( ) const
{
2022-10-16 16:42:39 +02:00
return m_dom_node - > document ( ) ;
2022-08-28 13:42:07 +02:00
}
2025-01-08 01:51:29 +01:00
// https://drafts.csswg.org/css-ui/#propdef-user-select
CSS : : UserSelect Node : : user_select_used_value ( ) const
{
// The used value is the same as the computed value, except:
auto computed_value = computed_values ( ) . user_select ( ) ;
// 1. on editable elements where the used value is always 'contain' regardless of the computed value
// 2. when the computed value is 'auto', in which case the used value is one of the other values as defined below
// For the purpose of this specification, an editable element is either an editing host or a mutable form control with
// textual content, such as textarea.
auto * form_control = dynamic_cast < HTML : : FormAssociatedTextControlElement const * > ( dom_node ( ) ) ;
// FIXME: Check if this needs to exclude input elements with types such as color or range, and if so, which ones exactly.
if ( ( dom_node ( ) & & dom_node ( ) - > is_editing_host ( ) ) | | ( form_control & & form_control - > is_mutable ( ) ) ) {
return CSS : : UserSelect : : Contain ;
} else if ( computed_value = = CSS : : UserSelect : : Auto ) {
// The used value of 'auto' is determined as follows:
// - On the '::before' and '::after' pseudo-elements, the used value is 'none'
if ( is_generated_for_before_pseudo_element ( ) | | is_generated_for_after_pseudo_element ( ) ) {
return CSS : : UserSelect : : None ;
}
// - If the element is an editable element, the used value is 'contain'
// NOTE: We already handled this above.
auto parent_element = parent ( ) ;
if ( parent_element ) {
auto parent_used_value = parent_element - > user_select_used_value ( ) ;
// - Otherwise, if the used value of user-select on the parent of this element is 'all', the used value is 'all'
if ( parent_used_value = = CSS : : UserSelect : : All ) {
return CSS : : UserSelect : : All ;
}
// - Otherwise, if the used value of user-select on the parent of this element is 'none', the used value is
// 'none'
if ( parent_used_value = = CSS : : UserSelect : : None ) {
return CSS : : UserSelect : : None ;
}
}
// - Otherwise, the used value is 'text'
return CSS : : UserSelect : : Text ;
}
return computed_value ;
}
2025-02-19 10:54:44 +01:00
bool NodeWithStyleAndBoxModelMetrics : : should_create_inline_continuation ( ) const
{
// This node must have an inline parent.
if ( ! parent ( ) )
return false ;
auto const & parent_display = parent ( ) - > display ( ) ;
if ( ! parent_display . is_inline_outside ( ) | | ! parent_display . is_flow_inside ( ) )
return false ;
// This node must not be inline itself or out of flow (which gets handled separately).
if ( display ( ) . is_inline_outside ( ) | | is_out_of_flow ( ) )
return false ;
// This node must not have `display: contents`; inline continuation gets handled by its children.
if ( display ( ) . is_contents ( ) )
return false ;
// Parent element must not be <foreignObject>
if ( is < SVG : : SVGForeignObjectElement > ( parent ( ) - > dom_node ( ) ) )
return false ;
2025-02-19 11:04:15 +01:00
// SVGBoxes are appended directly to their layout parent without changing the parent's (non-)inline behavior.
if ( is_svg_box ( ) )
return false ;
2025-02-19 10:54:44 +01:00
return true ;
}
2025-01-15 16:37:30 +01:00
void NodeWithStyleAndBoxModelMetrics : : propagate_style_along_continuation ( CSS : : ComputedProperties const & computed_style ) const
{
2025-02-04 23:05:37 +01:00
auto continuation = continuation_of_node ( ) ;
while ( continuation & & continuation - > is_anonymous ( ) )
continuation = continuation - > continuation_of_node ( ) ;
if ( continuation )
continuation - > apply_style ( computed_style ) ;
2025-01-15 16:37:30 +01:00
}
void NodeWithStyleAndBoxModelMetrics : : visit_edges ( Cell : : Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
visitor . visit ( m_continuation_of_node ) ;
}
2020-03-07 10:27:02 +01:00
}