2020-01-18 09:38:21 +01:00
/*
2022-03-24 17:38:05 +01:00
* Copyright ( c ) 2018 - 2022 , Andreas Kling < kling @ serenityos . org >
2020-01-18 09:38:21 +01:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 09:38:21 +01:00
*/
2021-01-01 16:42:44 +01:00
# include <AK/Demangle.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>
2021-11-18 15:01:28 +01:00
# include <LibWeb/HTML/BrowsingContext.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>
2021-09-08 11:27:46 +02:00
# include <LibWeb/Layout/InitialContainingBlock.h>
2020-11-22 15:53:01 +01:00
# include <LibWeb/Layout/Node.h>
2023-01-09 08:27:39 +03:00
# include <LibWeb/Layout/TableBox.h>
2021-01-01 18:55:47 +01:00
# include <LibWeb/Layout/TextNode.h>
2022-09-17 21:25:50 +02:00
# include <LibWeb/Platform/FontPlugin.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-20 18:20:34 +02:00
, m_browsing_context ( * document . browsing_context ( ) )
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
m_serial_id = document . next_layout_node_serial_id ( { } ) ;
2022-07-11 17:12:58 +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 ) ;
2022-10-20 18:20:34 +02:00
visitor . visit ( m_browsing_context ) ;
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
{
2021-09-08 11:27:46 +02:00
return computed_values ( ) . position ( ) ! = CSS : : Position : : Static | | is < InitialContainingBlock > ( * this ) ;
2020-06-05 16:54:28 +02:00
}
2022-04-01 20:58:27 +03:00
BlockContainer 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 ) )
2022-03-18 11:55:16 +01:00
return first_ancestor_of_type < BlockContainer > ( ) ;
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
if ( position = = CSS : : Position : : Absolute ) {
2020-06-05 16:54:28 +02:00
auto * ancestor = parent ( ) ;
while ( ancestor & & ! ancestor - > can_contain_boxes_with_position_absolute ( ) )
ancestor = ancestor - > parent ( ) ;
2021-10-06 20:02:41 +02:00
while ( ancestor & & ( ! is < BlockContainer > ( * ancestor ) | | ancestor - > is_anonymous ( ) ) )
2020-06-05 16:54:28 +02:00
ancestor = ancestor - > containing_block ( ) ;
2022-04-01 20:58:27 +03:00
return static_cast < BlockContainer const * > ( ancestor ) ;
2020-06-05 16:54:28 +02:00
}
2020-06-12 14:19:03 +02:00
if ( position = = CSS : : Position : : Fixed )
2020-06-05 16:54:28 +02:00
return & root ( ) ;
2022-03-18 11:55:16 +01:00
return first_ancestor_of_type < BlockContainer > ( ) ;
2019-07-01 07:28:37 +02:00
}
2019-09-25 12:40:37 +03:00
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 ;
2021-09-02 19:27:42 +01:00
if ( dom_node ( ) = = & document ( ) . root ( ) )
2021-05-07 19:03:25 +03:00
return true ;
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.
if ( position = = CSS : : Position : : Absolute | | position = = CSS : : Position : : Relative ) {
if ( computed_values ( ) . z_index ( ) . has_value ( ) ) {
return true ;
}
}
// Element with a position value fixed or sticky.
if ( position = = CSS : : Position : : Fixed | | position = = CSS : : Position : : 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
// 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 ;
2022-10-24 16:05:10 +01:00
// https://drafts.fxtf.org/filter-effects-2/#backdrop-filter-operation
// 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.
// Spec Note: This rule works in the same way as for the filter property.
if ( ! computed_values ( ) . backdrop_filter ( ) . is_none ( ) )
return true ;
2021-10-19 15:27:40 +02:00
return computed_values ( ) . opacity ( ) < 1.0f ;
2021-05-07 19:03:25 +03:00
}
2021-11-18 15:01:28 +01:00
HTML : : BrowsingContext const & Node : : browsing_context ( ) const
2020-06-14 16:45:45 +02:00
{
2022-10-20 18:20:34 +02:00
return * m_browsing_context ;
2020-06-14 16:45:45 +02:00
}
2021-11-18 15:01:28 +01:00
HTML : : BrowsingContext & Node : : browsing_context ( )
2020-06-14 16:45:45 +02:00
{
2022-10-20 18:20:34 +02:00
return * m_browsing_context ;
2020-06-14 16:45:45 +02:00
}
2022-04-01 20:58:27 +03:00
InitialContainingBlock 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 ( ) ;
}
2021-09-08 11:27:46 +02:00
InitialContainingBlock & 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
void Node : : set_needs_display ( )
2019-10-09 21:25:29 +02:00
{
2022-09-27 15:16:53 +02:00
auto * containing_block = this - > containing_block ( ) ;
if ( ! containing_block )
return ;
if ( ! containing_block - > paint_box ( ) )
return ;
containing_block - > paint_box ( ) - > for_each_fragment ( [ & ] ( auto & fragment ) {
if ( & fragment . layout_node ( ) = = this | | is_ancestor_of ( fragment . layout_node ( ) ) ) {
2022-11-03 12:49:54 +00:00
browsing_context ( ) . set_needs_display ( fragment . absolute_rect ( ) ) ;
2022-09-27 15:16:53 +02:00
}
return IterationDecision : : Continue ;
} ) ;
2019-10-20 09:14:12 +02:00
}
2022-11-08 11:31:24 +00:00
CSSPixelPoint Node : : box_type_agnostic_position ( ) const
2019-10-20 09:14:12 +02:00
{
2021-01-01 18:55:47 +01:00
if ( is < Box > ( * this ) )
2022-11-08 11:31:24 +00:00
return verify_cast < Box > ( * this ) . paint_box ( ) - > absolute_position ( ) ;
2021-02-23 20:42:32 +01:00
VERIFY ( is_inline ( ) ) ;
2022-11-08 11:31:24 +00:00
CSSPixelPoint position ;
2019-10-20 09:14:12 +02:00
if ( auto * block = containing_block ( ) ) {
2022-03-10 11:12:06 +01:00
block - > paint_box ( ) - > for_each_fragment ( [ & ] ( auto & fragment ) {
2019-10-20 09:14:12 +02:00
if ( & fragment . layout_node ( ) = = this | | is_ancestor_of ( fragment . layout_node ( ) ) ) {
2022-11-08 11:31:24 +00:00
position = fragment . absolute_rect ( ) . location ( ) ;
2019-10-20 09:14:12 +02:00
return IterationDecision : : Break ;
}
return IterationDecision : : Continue ;
} ) ;
}
return position ;
2019-10-09 21:25:29 +02:00
}
2020-03-07 10:27:02 +01:00
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
{
2021-01-06 11:07:02 +01:00
return has_style ( ) & & computed_values ( ) . position ( ) ! = CSS : : Position : : 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 ( ) ;
2020-06-12 14:19:03 +02:00
return position = = CSS : : Position : : Absolute | | position = = CSS : : Position : : Fixed ;
}
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 ( ) ;
2020-06-23 23:15:23 +02:00
return position = = CSS : : Position : : Fixed ;
}
2022-03-24 17:38:05 +01:00
NodeWithStyle : : NodeWithStyle ( DOM : : Document & document , DOM : : Node * node , NonnullRefPtr < CSS : : StyleProperties > computed_style )
2020-11-22 15:53:01 +01:00
: Node ( document , node )
2020-06-23 23:15:23 +02:00
{
m_has_style = true ;
2022-03-24 17:38:05 +01:00
apply_style ( * computed_style ) ;
2021-01-06 14:10:53 +01:00
}
NodeWithStyle : : NodeWithStyle ( DOM : : Document & document , DOM : : Node * node , CSS : : ComputedValues computed_values )
: Node ( document , node )
, m_computed_values ( move ( computed_values ) )
{
m_has_style = true ;
2022-09-17 21:25:50 +02:00
m_font = Platform : : FontPlugin : : the ( ) . default_font ( ) ;
2020-06-24 14:17:05 +02:00
}
2022-03-24 17:38:05 +01:00
void NodeWithStyle : : apply_style ( const CSS : : StyleProperties & computed_style )
2020-06-24 14:17:05 +02:00
{
2021-01-06 10:34:31 +01:00
auto & computed_values = static_cast < CSS : : MutableComputedValues & > ( m_computed_values ) ;
2020-06-24 14:17:05 +02:00
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.
2022-03-24 17:38:05 +01:00
m_font = computed_style . computed_font ( ) ;
2022-11-08 17:29:52 +00:00
computed_values . set_font_size ( computed_style . property ( CSS : : PropertyID : : FontSize ) - > to_length ( ) . to_px ( * this ) . value ( ) ) ;
2022-04-14 11:52:35 +01:00
computed_values . set_font_weight ( computed_style . property ( CSS : : PropertyID : : FontWeight ) - > to_integer ( ) ) ;
2022-03-24 17:38:05 +01:00
m_line_height = computed_style . line_height ( * this ) ;
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
{
2022-03-24 17:38:05 +01:00
auto attachments = computed_style . property ( CSS : : PropertyID : : BackgroundAttachment ) ;
auto clips = computed_style . property ( CSS : : PropertyID : : BackgroundClip ) ;
auto images = computed_style . property ( CSS : : PropertyID : : BackgroundImage ) ;
auto origins = computed_style . property ( CSS : : PropertyID : : BackgroundOrigin ) ;
auto positions = computed_style . property ( CSS : : PropertyID : : BackgroundPosition ) ;
auto repeats = computed_style . property ( CSS : : PropertyID : : BackgroundRepeat ) ;
auto sizes = computed_style . property ( CSS : : PropertyID : : BackgroundSize ) ;
2021-11-12 12:11:01 +00:00
auto count_layers = [ ] ( auto maybe_style_value ) - > size_t {
2022-04-14 11:52:35 +01:00
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 ;
} ;
2022-04-14 11:52:35 +01:00
auto value_for_layer = [ ] ( auto & style_value , size_t layer_index ) - > RefPtr < CSS : : StyleValue > {
2021-11-12 12:11:01 +00:00
if ( style_value - > is_value_list ( ) )
return style_value - > as_value_list ( ) . value_at ( layer_index , true ) ;
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 ) ) ;
layer_count = max ( layer_count , count_layers ( positions ) ) ;
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 ( ) ;
layer . background_image - > load_any_resources ( document ( ) ) ;
2022-07-12 00:28:19 +01:00
}
2021-11-12 12:11:01 +00:00
}
2021-11-12 16:30:21 +00:00
if ( auto attachment_value = value_for_layer ( attachments , layer_index ) ; attachment_value & & attachment_value - > has_identifier ( ) ) {
switch ( attachment_value - > to_identifier ( ) ) {
case CSS : : ValueID : : Fixed :
layer . attachment = CSS : : BackgroundAttachment : : Fixed ;
break ;
case CSS : : ValueID : : Local :
layer . attachment = CSS : : BackgroundAttachment : : Local ;
break ;
case CSS : : ValueID : : Scroll :
layer . attachment = CSS : : BackgroundAttachment : : Scroll ;
break ;
default :
break ;
}
}
auto as_box = [ ] ( auto value_id ) {
switch ( value_id ) {
case CSS : : ValueID : : BorderBox :
return CSS : : BackgroundBox : : BorderBox ;
case CSS : : ValueID : : ContentBox :
return CSS : : BackgroundBox : : ContentBox ;
case CSS : : ValueID : : PaddingBox :
return CSS : : BackgroundBox : : PaddingBox ;
default :
VERIFY_NOT_REACHED ( ) ;
}
} ;
if ( auto origin_value = value_for_layer ( origins , layer_index ) ; origin_value & & origin_value - > has_identifier ( ) ) {
layer . origin = as_box ( origin_value - > to_identifier ( ) ) ;
}
if ( auto clip_value = value_for_layer ( clips , layer_index ) ; clip_value & & clip_value - > has_identifier ( ) ) {
layer . clip = as_box ( clip_value - > to_identifier ( ) ) ;
}
if ( auto position_value = value_for_layer ( positions , layer_index ) ; position_value & & position_value - > is_position ( ) ) {
auto & position = position_value - > as_position ( ) ;
layer . position_edge_x = position . edge_x ( ) ;
layer . position_edge_y = position . edge_y ( ) ;
layer . position_offset_x = position . offset_x ( ) ;
layer . position_offset_y = position . offset_y ( ) ;
}
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 ( ) ;
} else if ( size_value - > has_identifier ( ) ) {
switch ( size_value - > to_identifier ( ) ) {
case CSS : : ValueID : : Contain :
layer . size_type = CSS : : BackgroundSize : : Contain ;
break ;
case CSS : : ValueID : : Cover :
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 ( ) ;
}
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
2022-04-13 19:33:56 +01:00
if ( auto box_sizing = computed_style . box_sizing ( ) ; box_sizing . has_value ( ) )
computed_values . set_box_sizing ( box_sizing . release_value ( ) ) ;
2021-10-05 16:55:02 +01:00
2022-03-24 17:38:05 +01:00
if ( auto maybe_font_variant = computed_style . font_variant ( ) ; maybe_font_variant . has_value ( ) )
2022-03-23 14:54:21 +01:00
computed_values . set_font_variant ( maybe_font_variant . release_value ( ) ) ;
2021-08-06 16:55:08 +01:00
// FIXME: BorderXRadius properties are now BorderRadiusStyleValues, so make use of that.
2022-03-24 17:38:05 +01:00
auto border_bottom_left_radius = computed_style . property ( CSS : : PropertyID : : BorderBottomLeftRadius ) ;
2022-06-12 15:05:47 +01:00
if ( border_bottom_left_radius - > is_border_radius ( ) ) {
computed_values . set_border_bottom_left_radius (
CSS : : BorderRadiusData {
border_bottom_left_radius - > as_border_radius ( ) . horizontal_radius ( ) ,
border_bottom_left_radius - > as_border_radius ( ) . vertical_radius ( ) } ) ;
}
2022-03-24 17:38:05 +01:00
auto border_bottom_right_radius = computed_style . property ( CSS : : PropertyID : : BorderBottomRightRadius ) ;
2022-06-12 15:05:47 +01:00
if ( border_bottom_right_radius - > is_border_radius ( ) ) {
computed_values . set_border_bottom_right_radius (
CSS : : BorderRadiusData {
border_bottom_right_radius - > as_border_radius ( ) . horizontal_radius ( ) ,
border_bottom_right_radius - > as_border_radius ( ) . vertical_radius ( ) } ) ;
}
2022-03-24 17:38:05 +01:00
auto border_top_left_radius = computed_style . property ( CSS : : PropertyID : : BorderTopLeftRadius ) ;
2022-06-12 15:05:47 +01:00
if ( border_top_left_radius - > is_border_radius ( ) ) {
computed_values . set_border_top_left_radius (
CSS : : BorderRadiusData {
border_top_left_radius - > as_border_radius ( ) . horizontal_radius ( ) ,
border_top_left_radius - > as_border_radius ( ) . vertical_radius ( ) } ) ;
}
2022-03-24 17:38:05 +01:00
auto border_top_right_radius = computed_style . property ( CSS : : PropertyID : : BorderTopRightRadius ) ;
2022-06-12 15:05:47 +01:00
if ( border_top_right_radius - > is_border_radius ( ) ) {
computed_values . set_border_top_right_radius (
CSS : : BorderRadiusData {
border_top_right_radius - > as_border_radius ( ) . horizontal_radius ( ) ,
border_top_right_radius - > as_border_radius ( ) . vertical_radius ( ) } ) ;
}
2022-03-24 17:38:05 +01:00
computed_values . set_display ( computed_style . display ( ) ) ;
2021-01-07 14:41:50 +01:00
2022-03-24 17:38:05 +01:00
auto flex_direction = computed_style . flex_direction ( ) ;
2021-01-18 17:41:57 +01:00
if ( flex_direction . has_value ( ) )
computed_values . set_flex_direction ( flex_direction . value ( ) ) ;
2022-03-24 17:38:05 +01:00
auto flex_wrap = computed_style . flex_wrap ( ) ;
2021-05-30 12:11:32 +02:00
if ( flex_wrap . has_value ( ) )
computed_values . set_flex_wrap ( flex_wrap . value ( ) ) ;
2022-03-24 17:38:05 +01:00
auto flex_basis = computed_style . flex_basis ( ) ;
2021-05-30 14:23:43 +02:00
if ( flex_basis . has_value ( ) )
computed_values . set_flex_basis ( flex_basis . value ( ) ) ;
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 ( ) ) ;
2022-09-15 08:31:19 +01:00
computed_values . set_backdrop_filter ( computed_style . backdrop_filter ( ) ) ;
2021-05-30 20:22:25 +02:00
2022-03-24 17:38:05 +01:00
auto justify_content = computed_style . justify_content ( ) ;
2021-07-16 18:38:26 +02:00
if ( justify_content . has_value ( ) )
computed_values . set_justify_content ( justify_content . value ( ) ) ;
2022-10-14 13:50:06 +02:00
auto align_content = computed_style . align_content ( ) ;
if ( align_content . has_value ( ) )
computed_values . set_align_content ( align_content . value ( ) ) ;
2022-03-24 17:38:05 +01:00
auto align_items = computed_style . align_items ( ) ;
2021-09-15 18:27:20 +02:00
if ( align_items . has_value ( ) )
computed_values . set_align_items ( align_items . value ( ) ) ;
2022-07-11 23:52:36 +02:00
auto align_self = computed_style . align_self ( ) ;
if ( align_self . has_value ( ) )
computed_values . set_align_self ( align_self . value ( ) ) ;
2022-07-22 16:05:11 +01:00
auto appearance = computed_style . appearance ( ) ;
if ( appearance . has_value ( ) )
computed_values . set_appearance ( appearance . value ( ) ) ;
2022-03-24 17:38:05 +01:00
auto position = computed_style . position ( ) ;
2021-10-13 18:54:00 +02:00
if ( position . has_value ( ) )
2021-01-06 10:34:31 +01:00
computed_values . set_position ( position . value ( ) ) ;
2020-12-14 18:38:02 +01:00
2022-03-24 17:38:05 +01:00
auto text_align = computed_style . text_align ( ) ;
2020-12-14 18:38:02 +01:00
if ( text_align . has_value ( ) )
2021-01-06 10:34:31 +01:00
computed_values . set_text_align ( text_align . value ( ) ) ;
2020-06-24 16:37:44 +02:00
2022-03-24 17:38:05 +01:00
auto text_justify = computed_style . text_justify ( ) ;
2022-03-12 19:31:32 +00:00
if ( text_align . has_value ( ) )
computed_values . set_text_justify ( text_justify . value ( ) ) ;
2022-03-24 17:38:05 +01:00
auto white_space = computed_style . white_space ( ) ;
2020-06-24 16:37:44 +02:00
if ( white_space . has_value ( ) )
2021-01-06 10:34:31 +01:00
computed_values . set_white_space ( white_space . value ( ) ) ;
2020-06-24 16:37:44 +02:00
2022-03-24 17:38:05 +01:00
auto float_ = computed_style . float_ ( ) ;
2020-06-26 15:08:42 +02:00
if ( float_ . has_value ( ) )
2021-01-06 10:34:31 +01:00
computed_values . set_float ( float_ . value ( ) ) ;
2020-06-26 15:08:42 +02:00
2022-03-24 17:38:05 +01:00
auto clear = computed_style . clear ( ) ;
2020-12-06 01:45:51 +01:00
if ( clear . has_value ( ) )
2021-01-06 10:34:31 +01:00
computed_values . set_clear ( clear . value ( ) ) ;
2020-12-06 01:45:51 +01:00
2022-03-24 17:38:05 +01:00
auto overflow_x = computed_style . overflow_x ( ) ;
2021-02-22 15:20:31 +01:00
if ( overflow_x . has_value ( ) )
computed_values . set_overflow_x ( overflow_x . value ( ) ) ;
2022-03-24 17:38:05 +01:00
auto overflow_y = computed_style . overflow_y ( ) ;
2021-02-22 15:20:31 +01:00
if ( overflow_y . has_value ( ) )
computed_values . set_overflow_y ( overflow_y . value ( ) ) ;
2022-03-24 17:38:05 +01:00
auto cursor = computed_style . cursor ( ) ;
2021-02-21 17:41:00 +00:00
if ( cursor . has_value ( ) )
computed_values . set_cursor ( cursor . value ( ) ) ;
2022-03-24 17:38:05 +01:00
auto image_rendering = computed_style . image_rendering ( ) ;
2022-02-18 12:21:27 +01:00
if ( image_rendering . has_value ( ) )
computed_values . set_image_rendering ( image_rendering . value ( ) ) ;
2022-03-24 17:38:05 +01:00
auto pointer_events = computed_style . pointer_events ( ) ;
2021-10-05 19:47:13 +01:00
if ( pointer_events . has_value ( ) )
computed_values . set_pointer_events ( pointer_events . value ( ) ) ;
2022-04-14 16:22:35 +01:00
computed_values . set_text_decoration_line ( computed_style . text_decoration_line ( ) ) ;
2020-12-15 13:36:27 +01:00
2022-03-24 17:38:05 +01:00
auto text_decoration_style = computed_style . text_decoration_style ( ) ;
2022-01-20 20:27:55 +01:00
if ( text_decoration_style . has_value ( ) )
computed_values . set_text_decoration_style ( text_decoration_style . value ( ) ) ;
2022-03-24 17:38:05 +01:00
auto text_transform = computed_style . text_transform ( ) ;
2020-12-15 14:15:49 +01:00
if ( text_transform . has_value ( ) )
2021-01-06 10:34:31 +01:00
computed_values . set_text_transform ( text_transform . value ( ) ) ;
2020-12-15 14:15:49 +01:00
2022-03-24 17:38:05 +01:00
if ( auto list_style_type = computed_style . list_style_type ( ) ; list_style_type . has_value ( ) )
2021-01-06 10:34:31 +01:00
computed_values . set_list_style_type ( list_style_type . value ( ) ) ;
2020-12-15 16:50:39 +01:00
2022-03-24 17:38:05 +01:00
auto list_style_image = computed_style . property ( CSS : : PropertyID : : ListStyleImage ) ;
2022-07-31 01:11:59 +01:00
if ( list_style_image - > is_abstract_image ( ) ) {
m_list_style_image = list_style_image - > as_abstract_image ( ) ;
m_list_style_image - > load_any_resources ( document ( ) ) ;
2021-10-29 09:00:30 -04:00
}
2022-03-24 17:38:05 +01:00
computed_values . set_color ( computed_style . color_or_fallback ( CSS : : PropertyID : : Color , * this , CSS : : InitialValues : : color ( ) ) ) ;
2020-12-15 16:13:05 +01: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
2022-03-24 17:38:05 +01:00
computed_values . set_text_shadow ( computed_style . text_shadow ( ) ) ;
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
2022-03-24 17:38:05 +01:00
if ( auto maybe_visibility = computed_style . visibility ( ) ; maybe_visibility . has_value ( ) )
2022-03-21 15:42:57 +01:00
computed_values . set_visibility ( maybe_visibility . release_value ( ) ) ;
2022-09-15 21:01:43 +02:00
m_visible = computed_values . opacity ( ) ! = 0 & & computed_values . visibility ( ) = = CSS : : Visibility : : Visible ;
2021-05-30 13:43:47 +02: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
2022-03-24 17:38:05 +01:00
computed_values . set_box_shadow ( computed_style . box_shadow ( ) ) ;
2021-07-23 21:22:31 +02:00
2022-03-24 17:38:05 +01:00
computed_values . set_transformations ( computed_style . transformations ( ) ) ;
computed_values . set_transform_origin ( computed_style . transform_origin ( ) ) ;
2021-09-18 17:20:00 +02:00
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 ( ) ) ;
border . line_style = computed_style . line_style ( style_property ) . value_or ( CSS : : LineStyle : : None ) ;
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 {
auto resolve_border_width = [ & ] ( ) {
auto value = computed_style . property ( width_property ) ;
if ( value - > is_calculated ( ) )
2022-11-08 17:29:52 +00:00
return CSS : : Length : : make_calculated ( value - > as_calculated ( ) ) . to_px ( * this ) . value ( ) ;
2022-11-24 21:34:28 +01:00
if ( value - > has_length ( ) )
2022-11-08 17:29:52 +00:00
return value - > to_length ( ) . to_px ( * this ) . value ( ) ;
2022-11-24 21:34:28 +01:00
if ( value - > is_identifier ( ) ) {
// FIXME: These values should depend on something, e.g. a font size.
switch ( value - > to_identifier ( ) ) {
case CSS : : ValueID : : Thin :
return 1.0f ;
case CSS : : ValueID : : Medium :
return 3.0f ;
case CSS : : ValueID : : Thick :
return 5.0f ;
default :
VERIFY_NOT_REACHED ( ) ;
}
}
VERIFY_NOT_REACHED ( ) ;
} ;
border . width = resolve_border_width ( ) ;
}
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
2022-03-24 17:38:05 +01:00
computed_values . set_content ( computed_style . content ( ) ) ;
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 ( ) ) ;
2022-02-24 16:52:58 +00:00
2022-04-14 11:52:35 +01:00
if ( auto fill = computed_style . property ( CSS : : PropertyID : : Fill ) ; fill - > has_color ( ) )
computed_values . set_fill ( fill - > to_color ( * this ) ) ;
if ( auto stroke = computed_style . property ( CSS : : PropertyID : : Stroke ) ; stroke - > has_color ( ) )
computed_values . set_stroke ( stroke - > to_color ( * this ) ) ;
auto stroke_width = computed_style . property ( CSS : : PropertyID : : StrokeWidth ) ;
// FIXME: Converting to pixels isn't really correct - values should be in "user units"
// https://svgwg.org/svg2-draft/coords.html#TermUserUnits
if ( stroke_width - > is_numeric ( ) )
computed_values . set_stroke_width ( CSS : : Length : : make_px ( stroke_width - > to_number ( ) ) ) ;
else
computed_values . set_stroke_width ( stroke_width - > to_length ( ) ) ;
2022-11-06 12:42:22 +01:00
computed_values . set_column_gap ( computed_style . size_value ( CSS : : PropertyID : : ColumnGap ) ) ;
computed_values . set_row_gap ( computed_style . size_value ( CSS : : PropertyID : : RowGap ) ) ;
2023-01-02 23:01:29 +01:00
if ( auto border_collapse = computed_style . border_collapse ( ) ; border_collapse . has_value ( ) )
computed_values . set_border_collapse ( border_collapse . value ( ) ) ;
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 ( ) ) ;
}
2022-12-04 18:02:33 +00:00
DeprecatedString 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 ( ) ) ;
if ( auto id = element . get_attribute ( HTML : : AttributeNames : : id ) ; ! id . is_null ( ) )
builder . appendff ( " #{} " , id ) ;
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
}
2022-12-06 01:12:49 +00:00
return builder . to_deprecated_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.
return CSS : : Display ( CSS : : Display : : Outside : : Inline , CSS : : Display : : Inside : : Flow ) ;
}
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
2022-10-17 14:41:50 +02:00
JS : : NonnullGCPtr < NodeWithStyle > NodeWithStyle : : create_anonymous_wrapper ( ) const
2021-01-06 14:10:53 +01:00
{
2022-10-17 14:41:50 +02:00
auto wrapper = heap ( ) . allocate_without_realm < BlockContainer > ( const_cast < DOM : : Document & > ( document ( ) ) , nullptr , m_computed_values . clone_inherited_values ( ) ) ;
2022-09-08 11:52:39 +02:00
static_cast < CSS : : MutableComputedValues & > ( wrapper - > m_computed_values ) . set_display ( CSS : : Display ( CSS : : Display : : Outside : : Block , CSS : : Display : : Inside : : Flow ) ) ;
2021-01-06 14:10:53 +01:00
wrapper - > m_font = m_font ;
wrapper - > m_line_height = m_line_height ;
2022-10-17 14:41:50 +02:00
return * wrapper ;
2021-01-06 14:10:53 +01:00
}
2023-01-09 08:27:39 +03:00
void NodeWithStyle : : reset_table_box_computed_values_used_by_wrapper_to_init_values ( )
{
VERIFY ( is < TableBox > ( * this ) ) ;
CSS : : MutableComputedValues & mutable_computed_values = static_cast < CSS : : MutableComputedValues & > ( m_computed_values ) ;
mutable_computed_values . set_position ( CSS : : Position : : Static ) ;
mutable_computed_values . set_float ( CSS : : Float : : None ) ;
mutable_computed_values . set_inset ( { CSS : : Length : : make_auto ( ) , CSS : : Length : : make_auto ( ) , CSS : : Length : : make_auto ( ) , CSS : : Length : : make_auto ( ) } ) ;
mutable_computed_values . set_margin ( { CSS : : Length : : make_px ( 0 ) , CSS : : Length : : make_px ( 0 ) , CSS : : Length : : make_px ( 0 ) , CSS : : Length : : make_px ( 0 ) } ) ;
}
2022-03-10 22:38:08 +01:00
void Node : : set_paintable ( RefPtr < Painting : : Paintable > paintable )
2022-03-10 15:50:57 +01:00
{
m_paintable = move ( paintable ) ;
}
2022-03-10 22:38:08 +01:00
RefPtr < 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 ( ) ;
}
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
}
2020-03-07 10:27:02 +01:00
}