tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 6699673df2d47a864ad4c5ed4f81086911c68c67
parent 1f82730a85acc22c822dd339c92f074c649fd0ce
Author: sickl8 <sickl8@protonmail.com>
Date:   Tue,  2 Dec 2025 14:06:08 +0000

Bug 1960699 - Fix blockification and deblockification of flex/grid items when wrapped inside `display: contents` elements. r=emilio,firefox-style-system-reviewers

- Added new inheritable style builder flag `CASCADE_BEYOND_DISPLAY_CONTENTS` with it's corresponding adjuster function
- Modified tests to also include the case where the `display: contents` wrapper stays the same but the container switches `display` type after the first style resolution

- Moved adjustment code to `set_bits`
- Renamed flag to `DISPLAY_CONTENTS_IN_ITEM_CONTAINER`

Differential Revision: https://phabricator.services.mozilla.com/D274679

Diffstat:
Mservo/components/style/properties/computed_value_flags.rs | 10+++++++++-
Mservo/components/style/style_adjuster.rs | 12++++++++++++
Mtesting/web-platform/tests/css/css-display/display-contents-blockify-dynamic.html | 38++++++++++++++++++++++++++++++++++++++
3 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/servo/components/style/properties/computed_value_flags.rs b/servo/components/style/properties/computed_value_flags.rs @@ -132,6 +132,12 @@ bitflags! { /// Whether this style considered a scope style rule. const CONSIDERED_NONTRIVIAL_SCOPED_STYLE = 1 << 26; + + /// Whether this style is that of a `display: contents` element that is either a direct + /// child of an item container or another `display: contents` element, the style of which + /// has this flag set, marked in order to cascade beyond them to the descendants of the + /// the item container that do generate a box. + const DIPLAY_CONTENTS_IN_ITEM_CONTAINER = 1 << 27; } } @@ -158,7 +164,9 @@ impl ComputedValueFlags { /// Flags that may be propagated to descendants. #[inline] fn maybe_inherited_flags() -> Self { - Self::inherited_flags() | Self::SHOULD_SUPPRESS_LINEBREAK + Self::inherited_flags() + | Self::SHOULD_SUPPRESS_LINEBREAK + | Self::DIPLAY_CONTENTS_IN_ITEM_CONTAINER } /// Flags that are an input to the cascade. diff --git a/servo/components/style/style_adjuster.rs b/servo/components/style/style_adjuster.rs @@ -276,6 +276,18 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { self.style .add_flags(ComputedValueFlags::IS_IN_OPACITY_ZERO_SUBTREE); } + } else if self + .style + .get_parent_box() + .clone_display() + .is_item_container() + || self + .style + .get_parent_flags() + .contains(ComputedValueFlags::DIPLAY_CONTENTS_IN_ITEM_CONTAINER) + { + self.style + .add_flags(ComputedValueFlags::DIPLAY_CONTENTS_IN_ITEM_CONTAINER); } if self.style.pseudo.is_some_and(|p| p.is_first_line()) { diff --git a/testing/web-platform/tests/css/css-display/display-contents-blockify-dynamic.html b/testing/web-platform/tests/css/css-display/display-contents-blockify-dynamic.html @@ -15,6 +15,22 @@ <span></span> </div> </div> +<div id="grid-to-block" style="display: grid"> + <div style="display: contents"> + <div style="display: contents"> + <button>button1</button> + <button id="deblockified">button2</button> + </div> + </div> +</div> +<div id="block-to-grid" style="display: block"> + <div style="display: contents"> + <div style="display: contents"> + <button>button1</button> + <button id="blockified">button2</button> + </div> + </div> +</div> <script> function display(el) { return getComputedStyle(el).display; @@ -31,4 +47,26 @@ test(function() { assert_equals(display(child), "block", "Grid child should get blockified"); assert_equals(display(grandChild), "inline", "Grid grand-child should get un-blockified when its parent's display stops being `contents`"); }, "Dynamic changes to `display` causing blockification of children are handled correctly"); + +test(() => { + let gridToBlock = document.getElementById("grid-to-block"); + let itemGrandChild = document.getElementById("deblockified"); + + assert_equals(display(gridToBlock), "grid", "Container should be a grid"); + assert_equals(display(itemGrandChild), "block", "Item should have been blockified"); + gridToBlock.style.display = "block"; + assert_equals(display(gridToBlock), "block", "Container should become a block"); + assert_equals(display(itemGrandChild), "inline-block", "Item should get de-blockified"); +}, "Dynamic changes to `display` from `grid` to `block` should cause children to get de-blockified despite being children of `display: contents` elements"); + +test(() => { + let blockToGrid = document.getElementById("block-to-grid"); + let itemGrandChild = document.getElementById("blockified"); + + assert_equals(display(blockToGrid), "block", "Container should be a block"); + assert_equals(display(itemGrandChild), "inline-block", "Item should not have been blockified"); + blockToGrid.style.display = "grid"; + assert_equals(display(blockToGrid), "grid", "Container should become a grid"); + assert_equals(display(itemGrandChild), "block", "Item should get blockified"); +}, "Dynamic changes to `display` from `block` to `grid` should cause children to get blockified despite being children of `display: contents` elements") </script>