mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-30 12:49:19 +00:00
LibWeb: Move containment checks to Layout::Node
Some checks are pending
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (arm64, macos-15, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (x86_64, ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
Some checks are pending
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (arm64, macos-15, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (x86_64, ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
It fits better there and avoids having to reach into the Element all the time.
This commit is contained in:
parent
4989c5c793
commit
a0be82b2cb
Notes:
github-actions[bot]
2025-05-13 12:32:25 +00:00
Author: https://github.com/Psychpsyo
Commit: a0be82b2cb
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4565
Reviewed-by: https://github.com/gmta
Reviewed-by: https://github.com/kalenikaliaksandr
10 changed files with 145 additions and 169 deletions
|
@ -1333,9 +1333,6 @@ void Document::update_layout(UpdateLayoutReason reason)
|
|||
});
|
||||
|
||||
m_layout_root->for_each_in_inclusive_subtree_of_type<Layout::Box>([&](auto& child) {
|
||||
if (auto dom_node = child.dom_node(); dom_node && dom_node->is_element()) {
|
||||
child.set_has_size_containment(as<Element>(*dom_node).has_size_containment());
|
||||
}
|
||||
if (child.needs_layout_update()) {
|
||||
child.reset_cached_intrinsic_sizes();
|
||||
}
|
||||
|
|
|
@ -3188,131 +3188,6 @@ bool Element::skips_its_contents()
|
|||
return false;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/css-contain-2/#containment-size
|
||||
bool Element::has_size_containment() const
|
||||
{
|
||||
// However, giving an element size containment has no effect if any of the following are true:
|
||||
|
||||
// - if the element does not generate a principal box (as is the case with 'display: contents' or 'display: none')
|
||||
if (!layout_node())
|
||||
return false;
|
||||
|
||||
// - if its inner display type is 'table'
|
||||
if (layout_node()->display().is_table_inside())
|
||||
return false;
|
||||
|
||||
// - if its principal box is an internal table box
|
||||
if (layout_node()->display().is_internal_table())
|
||||
return false;
|
||||
|
||||
// - if its principal box is an internal ruby box or a non-atomic inline-level box
|
||||
// FIXME: Implement this.
|
||||
|
||||
if (computed_properties()->contain().size_containment)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
// https://drafts.csswg.org/css-contain-2/#containment-inline-size
|
||||
bool Element::has_inline_size_containment() const
|
||||
{
|
||||
// Giving an element inline-size containment has no effect if any of the following are true:
|
||||
|
||||
// - if the element does not generate a principal box (as is the case with 'display: contents' or 'display: none')
|
||||
if (!layout_node())
|
||||
return false;
|
||||
|
||||
// - if its inner display type is 'table'
|
||||
if (layout_node()->display().is_table_inside())
|
||||
return false;
|
||||
|
||||
// - if its principal box is an internal table box
|
||||
if (layout_node()->display().is_internal_table())
|
||||
return false;
|
||||
|
||||
// - if its principal box is an internal ruby box or a non-atomic inline-level box
|
||||
// FIXME: Implement this.
|
||||
|
||||
if (computed_properties()->contain().inline_size_containment)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
// https://drafts.csswg.org/css-contain-2/#containment-layout
|
||||
bool Element::has_layout_containment() const
|
||||
{
|
||||
// However, giving an element layout containment has no effect if any of the following are true:
|
||||
|
||||
// - if the element does not generate a principal box (as is the case with 'display: contents' or 'display: none')
|
||||
if (!layout_node())
|
||||
return false;
|
||||
|
||||
// - if its principal box is an internal table box other than 'table-cell'
|
||||
if (layout_node()->display().is_internal_table() && !layout_node()->display().is_table_cell())
|
||||
return false;
|
||||
|
||||
// - if its principal box is an internal ruby box or a non-atomic inline-level box
|
||||
// FIXME: Implement this.
|
||||
|
||||
if (computed_properties()->contain().layout_containment)
|
||||
return true;
|
||||
|
||||
// https://drafts.csswg.org/css-contain-2/#valdef-content-visibility-auto
|
||||
// Changes the used value of the 'contain' property so as to turn on layout containment, style containment, and
|
||||
// paint containment for the element.
|
||||
if (computed_properties()->content_visibility() == CSS::ContentVisibility::Auto)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
// https://drafts.csswg.org/css-contain-2/#containment-style
|
||||
bool Element::has_style_containment() const
|
||||
{
|
||||
// However, giving an element style containment has no effect if any of the following are true:
|
||||
|
||||
// - if the element does not generate a principal box (as is the case with 'display: contents' or 'display: none')
|
||||
if (!layout_node())
|
||||
return false;
|
||||
|
||||
if (computed_properties()->contain().style_containment)
|
||||
return true;
|
||||
|
||||
// https://drafts.csswg.org/css-contain-2/#valdef-content-visibility-auto
|
||||
// Changes the used value of the 'contain' property so as to turn on layout containment, style containment, and
|
||||
// paint containment for the element.
|
||||
if (computed_properties()->content_visibility() == CSS::ContentVisibility::Auto)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
// https://drafts.csswg.org/css-contain-2/#containment-paint
|
||||
bool Element::has_paint_containment() const
|
||||
{
|
||||
// However, giving an element paint containment has no effect if any of the following are true:
|
||||
|
||||
// - if the element does not generate a principal box (as is the case with 'display: contents' or 'display: none')
|
||||
if (!layout_node())
|
||||
return false;
|
||||
|
||||
// - if its principal box is an internal table box other than 'table-cell'
|
||||
if (layout_node()->display().is_internal_table() && !layout_node()->display().is_table_cell())
|
||||
return false;
|
||||
|
||||
// - if its principal box is an internal ruby box or a non-atomic inline-level box
|
||||
// FIXME: Implement this
|
||||
|
||||
if (computed_properties()->contain().paint_containment)
|
||||
return true;
|
||||
|
||||
// https://drafts.csswg.org/css-contain-2/#valdef-content-visibility-auto
|
||||
// Changes the used value of the 'contain' property so as to turn on layout containment, style containment, and
|
||||
// paint containment for the element.
|
||||
if (computed_properties()->content_visibility() == CSS::ContentVisibility::Auto)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t Element::number_of_owned_list_items() const
|
||||
{
|
||||
auto number_of_owned_li_elements = 0;
|
||||
|
|
|
@ -422,13 +422,6 @@ public:
|
|||
// https://drafts.csswg.org/css-contain-2/#skips-its-contents
|
||||
bool skips_its_contents();
|
||||
|
||||
// https://drafts.csswg.org/css-contain-2/#containment-types
|
||||
bool has_size_containment() const;
|
||||
bool has_inline_size_containment() const;
|
||||
bool has_layout_containment() const;
|
||||
bool has_style_containment() const;
|
||||
bool has_paint_containment() const;
|
||||
|
||||
bool matches_enabled_pseudo_class() const;
|
||||
bool matches_disabled_pseudo_class() const;
|
||||
bool matches_checked_pseudo_class() const;
|
||||
|
|
|
@ -34,7 +34,7 @@ Optional<CSSPixels> Box::natural_width() const
|
|||
// https://drafts.csswg.org/css-contain-2/#containment-size
|
||||
// Replaced elements must be treated as having a natural width and height of 0 and no natural aspect
|
||||
// ratio.
|
||||
if (m_has_size_containment)
|
||||
if (has_size_containment())
|
||||
return 0;
|
||||
return m_natural_width;
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ Optional<CSSPixels> Box::natural_height() const
|
|||
// https://drafts.csswg.org/css-contain-2/#containment-size
|
||||
// Replaced elements must be treated as having a natural width and height of 0 and no natural aspect
|
||||
// ratio.
|
||||
if (m_has_size_containment)
|
||||
if (has_size_containment())
|
||||
return 0;
|
||||
return m_natural_height;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ Optional<CSSPixelFraction> Box::natural_aspect_ratio() const
|
|||
// https://drafts.csswg.org/css-contain-2/#containment-size
|
||||
// Replaced elements must be treated as having a natural width and height of 0 and no natural aspect
|
||||
// ratio.
|
||||
if (m_has_size_containment)
|
||||
if (has_size_containment())
|
||||
return {};
|
||||
return m_natural_aspect_ratio;
|
||||
}
|
||||
|
|
|
@ -40,9 +40,6 @@ public:
|
|||
bool has_natural_height() const { return natural_height().has_value(); }
|
||||
bool has_natural_aspect_ratio() const { return natural_aspect_ratio().has_value(); }
|
||||
|
||||
bool has_size_containment() const { return m_has_size_containment; }
|
||||
void set_has_size_containment(bool value) { m_has_size_containment = value; }
|
||||
|
||||
void set_natural_width(Optional<CSSPixels> width) { m_natural_width = width; }
|
||||
void set_natural_height(Optional<CSSPixels> height) { m_natural_height = height; }
|
||||
void set_natural_aspect_ratio(Optional<CSSPixelFraction> ratio) { m_natural_aspect_ratio = ratio; }
|
||||
|
@ -82,8 +79,6 @@ private:
|
|||
Optional<CSSPixels> m_natural_height;
|
||||
Optional<CSSPixelFraction> m_natural_aspect_ratio;
|
||||
|
||||
bool m_has_size_containment { false };
|
||||
|
||||
Vector<GC::Ref<Node>> m_contained_abspos_children;
|
||||
|
||||
OwnPtr<IntrinsicSizes> mutable m_cached_intrinsic_sizes;
|
||||
|
|
|
@ -97,11 +97,8 @@ bool FormattingContext::creates_block_formatting_context(Box const& box)
|
|||
// https://drafts.csswg.org/css-contain-2/#containment-types
|
||||
// 1. The layout containment box establishes an independent formatting context.
|
||||
// 4. The paint containment box establishes an independent formatting context.
|
||||
if (box.dom_node() && box.dom_node()->is_element()) {
|
||||
auto element = as<DOM::Element>(box.dom_node());
|
||||
if (element->has_layout_containment() || element->has_paint_containment())
|
||||
if (box.has_layout_containment() || box.has_paint_containment())
|
||||
return true;
|
||||
}
|
||||
|
||||
if (box.parent()) {
|
||||
auto parent_display = box.parent()->display();
|
||||
|
|
|
@ -98,11 +98,8 @@ bool Node::can_contain_boxes_with_position_absolute() const
|
|||
// 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())
|
||||
if (has_layout_containment() || has_paint_containment())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -244,11 +241,8 @@ bool Node::establishes_stacking_context() const
|
|||
// 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())
|
||||
if (has_layout_containment() || has_paint_containment())
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://drafts.fxtf.org/compositing/#mix-blend-mode
|
||||
// Applying a blendmode other than normal to the element must establish a new stacking context.
|
||||
|
@ -959,6 +953,7 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
|
|||
computed_values.set_isolation(computed_style.isolation());
|
||||
computed_values.set_mix_blend_mode(computed_style.mix_blend_mode());
|
||||
computed_values.set_view_transition_name(computed_style.view_transition_name());
|
||||
computed_values.set_contain(computed_style.contain());
|
||||
|
||||
computed_values.set_caret_color(computed_style.caret_color(*this));
|
||||
|
||||
|
@ -1240,6 +1235,126 @@ CSS::UserSelect Node::user_select_used_value() const
|
|||
return computed_value;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/css-contain-2/#containment-size
|
||||
bool Node::has_size_containment() const
|
||||
{
|
||||
// However, giving an element size containment has no effect if any of the following are true:
|
||||
|
||||
// - if the element does not generate a principal box (as is the case with 'display: contents' or 'display: none')
|
||||
// Note: This is the principal box
|
||||
|
||||
// - if its inner display type is 'table'
|
||||
if (display().is_table_inside())
|
||||
return false;
|
||||
|
||||
// - if its principal box is an internal table box
|
||||
if (display().is_internal_table())
|
||||
return false;
|
||||
|
||||
// - if its principal box is an internal ruby box or a non-atomic inline-level box
|
||||
// FIXME: Implement this.
|
||||
|
||||
if (computed_values().contain().size_containment)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
// https://drafts.csswg.org/css-contain-2/#containment-inline-size
|
||||
bool Node::has_inline_size_containment() const
|
||||
{
|
||||
// Giving an element inline-size containment has no effect if any of the following are true:
|
||||
|
||||
// - if the element does not generate a principal box (as is the case with 'display: contents' or 'display: none')
|
||||
// Note: This is the principal box
|
||||
|
||||
// - if its inner display type is 'table'
|
||||
if (display().is_table_inside())
|
||||
return false;
|
||||
|
||||
// - if its principal box is an internal table box
|
||||
if (display().is_internal_table())
|
||||
return false;
|
||||
|
||||
// - if its principal box is an internal ruby box or a non-atomic inline-level box
|
||||
// FIXME: Implement this.
|
||||
|
||||
if (computed_values().contain().inline_size_containment)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
// https://drafts.csswg.org/css-contain-2/#containment-layout
|
||||
bool Node::has_layout_containment() const
|
||||
{
|
||||
// However, giving an element layout containment has no effect if any of the following are true:
|
||||
|
||||
// - if the element does not generate a principal box (as is the case with 'display: contents' or 'display: none')
|
||||
// Note: This is the principal box
|
||||
|
||||
// - if its principal box is an internal table box other than 'table-cell'
|
||||
if (display().is_internal_table() && !display().is_table_cell())
|
||||
return false;
|
||||
|
||||
// - if its principal box is an internal ruby box or a non-atomic inline-level box
|
||||
// FIXME: Implement this.
|
||||
|
||||
if (computed_values().contain().layout_containment)
|
||||
return true;
|
||||
|
||||
// https://drafts.csswg.org/css-contain-2/#valdef-content-visibility-auto
|
||||
// Changes the used value of the 'contain' property so as to turn on layout containment, style containment, and
|
||||
// paint containment for the element.
|
||||
if (computed_values().content_visibility() == CSS::ContentVisibility::Auto)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
// https://drafts.csswg.org/css-contain-2/#containment-style
|
||||
bool Node::has_style_containment() const
|
||||
{
|
||||
// However, giving an element style containment has no effect if any of the following are true:
|
||||
|
||||
// - if the element does not generate a principal box (as is the case with 'display: contents' or 'display: none')
|
||||
// Note: This is the principal box
|
||||
|
||||
if (computed_values().contain().style_containment)
|
||||
return true;
|
||||
|
||||
// https://drafts.csswg.org/css-contain-2/#valdef-content-visibility-auto
|
||||
// Changes the used value of the 'contain' property so as to turn on layout containment, style containment, and
|
||||
// paint containment for the element.
|
||||
if (computed_values().content_visibility() == CSS::ContentVisibility::Auto)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
// https://drafts.csswg.org/css-contain-2/#containment-paint
|
||||
bool Node::has_paint_containment() const
|
||||
{
|
||||
// However, giving an element paint containment has no effect if any of the following are true:
|
||||
|
||||
// - if the element does not generate a principal box (as is the case with 'display: contents' or 'display: none')
|
||||
// Note: This is the principal box
|
||||
|
||||
// - if its principal box is an internal table box other than 'table-cell'
|
||||
if (display().is_internal_table() && !display().is_table_cell())
|
||||
return false;
|
||||
|
||||
// - if its principal box is an internal ruby box or a non-atomic inline-level box
|
||||
// FIXME: Implement this
|
||||
|
||||
if (computed_values().contain().paint_containment)
|
||||
return true;
|
||||
|
||||
// https://drafts.csswg.org/css-contain-2/#valdef-content-visibility-auto
|
||||
// Changes the used value of the 'contain' property so as to turn on layout containment, style containment, and
|
||||
// paint containment for the element.
|
||||
if (computed_values().content_visibility() == CSS::ContentVisibility::Auto)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NodeWithStyleAndBoxModelMetrics::should_create_inline_continuation() const
|
||||
{
|
||||
// This node must have an inline parent.
|
||||
|
|
|
@ -192,6 +192,13 @@ public:
|
|||
// https://drafts.csswg.org/css-ui/#propdef-user-select
|
||||
CSS::UserSelect user_select_used_value() const;
|
||||
|
||||
// https://drafts.csswg.org/css-contain-2/#containment-types
|
||||
bool has_size_containment() const;
|
||||
bool has_inline_size_containment() const;
|
||||
bool has_layout_containment() const;
|
||||
bool has_style_containment() const;
|
||||
bool has_paint_containment() const;
|
||||
|
||||
[[nodiscard]] bool has_been_wrapped_in_table_wrapper() const { return m_has_been_wrapped_in_table_wrapper; }
|
||||
void set_has_been_wrapped_in_table_wrapper(bool value) { m_has_been_wrapped_in_table_wrapper = value; }
|
||||
|
||||
|
|
|
@ -626,7 +626,7 @@ void TreeBuilder::update_layout_tree(DOM::Node& dom_node, TreeBuilder::Context&
|
|||
// Giving an element style containment has the following effects:
|
||||
// 2. The effects of the 'content' property’s 'open-quote', 'close-quote', 'no-open-quote' and 'no-close-quote' must
|
||||
// be scoped to the element’s sub-tree.
|
||||
if (dom_node.is_element() && (static_cast<DOM::Element&>(dom_node)).has_style_containment()) {
|
||||
if (layout_node->has_style_containment()) {
|
||||
m_quote_nesting_level = prior_quote_nesting_level;
|
||||
}
|
||||
|
||||
|
|
|
@ -129,8 +129,7 @@ void ViewportPaintable::assign_clip_frames()
|
|||
auto overflow_y = paintable_box.computed_values().overflow_y();
|
||||
// Note: Overflow may be clip on one axis and visible on the other.
|
||||
auto has_hidden_overflow = overflow_x != CSS::Overflow::Visible || overflow_y != CSS::Overflow::Visible;
|
||||
auto element = as_if<DOM::Element>(paintable_box.layout_node().dom_node());
|
||||
if (has_hidden_overflow || paintable_box.get_clip_rect().has_value() || (element && element->has_paint_containment())) {
|
||||
if (has_hidden_overflow || paintable_box.get_clip_rect().has_value() || paintable_box.layout_node().has_paint_containment()) {
|
||||
auto clip_frame = adopt_ref(*new ClipFrame());
|
||||
clip_state.set(paintable_box, move(clip_frame));
|
||||
}
|
||||
|
@ -185,15 +184,13 @@ void ViewportPaintable::assign_clip_frames()
|
|||
// any such mechanism through other properties, such as overflow, resize, or text-overflow.
|
||||
// NOTE: This clipping shape respects overflow-clip-margin, allowing an element with paint containment
|
||||
// to still slightly overflow its normal bounds.
|
||||
if (auto element = as_if<DOM::Element>(block->dom_node())) {
|
||||
if (element->has_paint_containment()) {
|
||||
if (block->has_paint_containment()) {
|
||||
// NOTE: Note: The behavior is described in this paragraph is equivalent to changing 'overflow-x: visible' into
|
||||
// 'overflow-x: clip' and 'overflow-y: visible' into 'overflow-y: clip' at used value time, while leaving other
|
||||
// values of 'overflow-x' and 'overflow-y' unchanged.
|
||||
clip_x = true;
|
||||
clip_y = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (clip_x || clip_y) {
|
||||
// https://drafts.csswg.org/css-overflow-3/#corner-clipping
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue