style: Fix style containment not triggered by 'contain'

'container-type' and 'content-visibility' can trigger various kinds of
containment, but this was done via nsStyleDisplay::EffectiveContainment,
to avoid affecting the computed value of 'contain'.

This was fine except for style containment, which needs to set the flag
SELF_OR_ANCESTOR_HAS_CONTAIN_STYLE in order to really work, but this was
only done with 'contain: style'.

So this patch removes nsStyleDisplay::EffectiveContainment, and instead
uses two fields for containment: mContain and mEffectiveContainment.
This is somewhat analogous to mDisplay and mOriginalDisplay, though in
that case the computed value is the modified display.

Also fixes a typo in IsContainStyle() that made it return true for any
kind of containment, not just for style containment.

Differential Revision: https://phabricator.services.mozilla.com/D163779
This commit is contained in:
Oriol Brufau 2022-12-05 11:59:38 +00:00 committed by Martin Robinson
parent 60bd00980d
commit 7ec4c53266
2 changed files with 81 additions and 5 deletions

View file

@ -1127,7 +1127,7 @@ fn static_assert() {
${impl_copy_animation_value(ident, gecko_ffi_name)}
</%def>
<% skip_box_longhands= """display""" %>
<% skip_box_longhands= """display contain""" %>
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
#[inline]
pub fn set_display(&mut self, v: longhands::display::computed_value::T) {
@ -1137,8 +1137,7 @@ fn static_assert() {
#[inline]
pub fn copy_display_from(&mut self, other: &Self) {
self.gecko.mDisplay = other.gecko.mDisplay;
self.gecko.mOriginalDisplay = other.gecko.mDisplay;
self.set_display(other.gecko.mDisplay);
}
#[inline]
@ -1159,6 +1158,40 @@ fn static_assert() {
pub fn clone_display(&self) -> longhands::display::computed_value::T {
self.gecko.mDisplay
}
#[inline]
pub fn set_contain(&mut self, v: longhands::contain::computed_value::T) {
self.gecko.mContain = v;
self.gecko.mEffectiveContainment = v;
}
#[inline]
pub fn copy_contain_from(&mut self, other: &Self) {
self.set_contain(other.gecko.mContain);
}
#[inline]
pub fn reset_contain(&mut self, other: &Self) {
self.copy_contain_from(other)
}
#[inline]
pub fn clone_contain(&self) -> longhands::contain::computed_value::T {
self.gecko.mContain
}
#[inline]
pub fn set_effective_containment(
&mut self,
v: longhands::contain::computed_value::T
) {
self.gecko.mEffectiveContainment = v;
}
#[inline]
pub fn clone_effective_containment(&self) -> longhands::contain::computed_value::T {
self.gecko.mEffectiveContainment
}
</%self:impl_trait>
<%def name="simple_image_array_property(name, shorthand, field_name)">

View file

@ -7,8 +7,9 @@
use crate::computed_value_flags::ComputedValueFlags;
use crate::dom::TElement;
#[cfg(feature = "gecko")]
use crate::properties::longhands::contain::SpecifiedValue;
use crate::properties::longhands::contain::computed_value::T as Contain;
use crate::properties::longhands::container_type::computed_value::T as ContainerType;
use crate::properties::longhands::content_visibility::computed_value::T as ContentVisibility;
use crate::properties::longhands::display::computed_value::T as Display;
use crate::properties::longhands::float::computed_value::T as Float;
use crate::properties::longhands::position::computed_value::T as Position;
@ -465,6 +466,47 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
}
}
fn adjust_for_contain(&mut self) {
let box_style = self.style.get_box();
debug_assert_eq!(box_style.clone_contain(), box_style.clone_effective_containment());
let container_type = box_style.clone_container_type();
let content_visibility = box_style.clone_content_visibility();
if container_type == ContainerType::Normal &&
content_visibility == ContentVisibility::Visible
{
return;
}
let old_contain = box_style.clone_contain();
let mut new_contain = old_contain;
match content_visibility {
ContentVisibility::Visible => {},
// `content-visibility:auto` also applies size containment when content
// is not relevant (and therefore skipped). This is checked in
// nsIFrame::GetContainSizeAxes.
ContentVisibility::Auto => new_contain.insert(
Contain::LAYOUT | Contain::PAINT | Contain::STYLE),
ContentVisibility::Hidden => new_contain.insert(
Contain::LAYOUT | Contain::PAINT | Contain::SIZE | Contain::STYLE),
}
match container_type {
ContainerType::Normal => {},
// https://drafts.csswg.org/css-contain-3/#valdef-container-type-inline-size:
// Applies layout containment, style containment, and inline-size
// containment to the principal box.
ContainerType::InlineSize => new_contain.insert(
Contain::LAYOUT | Contain::STYLE | Contain::INLINE_SIZE),
// https://drafts.csswg.org/css-contain-3/#valdef-container-type-size:
// Applies layout containment, style containment, and size
// containment to the principal box.
ContainerType::Size => new_contain.insert(
Contain::LAYOUT | Contain::STYLE | Contain::SIZE),
}
if new_contain == old_contain {
return;
}
self.style.mutate_box().set_effective_containment(new_contain);
}
/// Handles the relevant sections in:
///
/// https://drafts.csswg.org/css-display/#unbox-html
@ -899,6 +941,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
self.adjust_for_webkit_line_clamp();
self.adjust_for_position();
self.adjust_for_overflow();
self.adjust_for_contain();
#[cfg(feature = "gecko")]
{
self.adjust_for_table_text_align();