aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout_2020
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2024-03-27 12:57:27 +0100
committerGitHub <noreply@github.com>2024-03-27 11:57:27 +0000
commitb8c82c1ab00dc8d3738523b60afd9cdcf548e83c (patch)
treec4ba2c6921474efc91be5b86c39840b458700e18 /components/layout_2020
parent15cb9dd5fcdee81c80c5c19b12bb50504754c2ad (diff)
downloadservo-b8c82c1ab00dc8d3738523b60afd9cdcf548e83c.tar.gz
servo-b8c82c1ab00dc8d3738523b60afd9cdcf548e83c.zip
layout: Allow transforming inline replaced elements (#31833)
This requires passing through information about whether or not the element in question is replaced when checking to see if it's transformable and transitively all functions that make decisions about containing blocks. A new FragmentFlag is added to help track this -- it will be set on both the replaced items BoxFragment container as well as the Fragment for the replaced item itself. Fixes #31806.
Diffstat (limited to 'components/layout_2020')
-rw-r--r--components/layout_2020/display_list/stacking_context.rs12
-rw-r--r--components/layout_2020/formatting_contexts.rs16
-rw-r--r--components/layout_2020/fragment_tree/base_fragment.rs3
-rw-r--r--components/layout_2020/fragment_tree/fragment.rs4
-rw-r--r--components/layout_2020/positioned.rs11
-rw-r--r--components/layout_2020/style_ext.rs40
-rw-r--r--components/layout_2020/table/layout.rs10
7 files changed, 63 insertions, 33 deletions
diff --git a/components/layout_2020/display_list/stacking_context.rs b/components/layout_2020/display_list/stacking_context.rs
index bdca1e5d77a..504725ae7c5 100644
--- a/components/layout_2020/display_list/stacking_context.rs
+++ b/components/layout_2020/display_list/stacking_context.rs
@@ -474,7 +474,7 @@ impl StackingContext {
if effects.filter.0.is_empty() &&
effects.opacity == 1.0 &&
effects.mix_blend_mode == ComputedMixBlendMode::Normal &&
- !style.has_transform_or_perspective()
+ !style.has_transform_or_perspective(FragmentFlags::empty())
{
return false;
}
@@ -896,7 +896,7 @@ struct ReferenceFrameData {
impl BoxFragment {
fn get_stacking_context_type(&self) -> Option<StackingContextType> {
- if self.style.establishes_stacking_context() {
+ if self.style.establishes_stacking_context(self.base.flags) {
return Some(StackingContextType::RealStackingContext);
}
@@ -986,7 +986,7 @@ impl BoxFragment {
// properties will be replaced before recursing into children.
assert!(self
.style
- .establishes_containing_block_for_all_descendants());
+ .establishes_containing_block_for_all_descendants(self.base.flags));
let adjusted_containing_block = ContainingBlock::new(
containing_block
.rect
@@ -1168,7 +1168,7 @@ impl BoxFragment {
// absolute and fixed descendants.
let new_containing_block_info = if self
.style
- .establishes_containing_block_for_all_descendants()
+ .establishes_containing_block_for_all_descendants(self.base.flags)
{
containing_block_info.new_for_absolute_and_fixed_descendants(
&for_non_absolute_descendants,
@@ -1176,7 +1176,7 @@ impl BoxFragment {
)
} else if self
.style
- .establishes_containing_block_for_absolute_descendants()
+ .establishes_containing_block_for_absolute_descendants(self.base.flags)
{
containing_block_info.new_for_absolute_descendants(
&for_non_absolute_descendants,
@@ -1389,7 +1389,7 @@ impl BoxFragment {
&self,
containing_block_rect: &PhysicalRect<Length>,
) -> Option<ReferenceFrameData> {
- if !self.style.has_transform_or_perspective() {
+ if !self.style.has_transform_or_perspective(self.base.flags) {
return None;
}
diff --git a/components/layout_2020/formatting_contexts.rs b/components/layout_2020/formatting_contexts.rs
index 347e88ad96e..1b15baa7eca 100644
--- a/components/layout_2020/formatting_contexts.rs
+++ b/components/layout_2020/formatting_contexts.rs
@@ -16,7 +16,7 @@ use crate::dom::NodeExt;
use crate::dom_traversal::{Contents, NodeAndStyleInfo};
use crate::flexbox::FlexContainer;
use crate::flow::BlockFormattingContext;
-use crate::fragment_tree::{BaseFragmentInfo, Fragment};
+use crate::fragment_tree::{BaseFragmentInfo, Fragment, FragmentFlags};
use crate::positioned::PositioningContext;
use crate::replaced::ReplacedContent;
use crate::sizing::{self, ContentSizes};
@@ -131,11 +131,15 @@ impl IndependentFormattingContext {
contents,
})
},
- Err(contents) => Self::Replaced(ReplacedFormattingContext {
- base_fragment_info: node_and_style_info.into(),
- style: Arc::clone(&node_and_style_info.style),
- contents,
- }),
+ Err(contents) => {
+ let mut base_fragment_info: BaseFragmentInfo = node_and_style_info.into();
+ base_fragment_info.flags.insert(FragmentFlags::IS_REPLACED);
+ Self::Replaced(ReplacedFormattingContext {
+ base_fragment_info,
+ style: Arc::clone(&node_and_style_info.style),
+ contents,
+ })
+ },
}
}
diff --git a/components/layout_2020/fragment_tree/base_fragment.rs b/components/layout_2020/fragment_tree/base_fragment.rs
index ac29bcc976d..b5e7fb3fbc5 100644
--- a/components/layout_2020/fragment_tree/base_fragment.rs
+++ b/components/layout_2020/fragment_tree/base_fragment.rs
@@ -88,6 +88,9 @@ bitflags! {
const IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT = 0b00000001;
/// Whether or not the node that created this Fragment is a `<br>` element.
const IS_BR_ELEMENT = 0b00000010;
+ /// Whether or not this Fragment was created to contain a replaced element or is
+ /// a replaced element.
+ const IS_REPLACED = 0b00000100;
}
}
diff --git a/components/layout_2020/fragment_tree/fragment.rs b/components/layout_2020/fragment_tree/fragment.rs
index 151a004aa13..b13fab0ddd4 100644
--- a/components/layout_2020/fragment_tree/fragment.rs
+++ b/components/layout_2020/fragment_tree/fragment.rs
@@ -192,12 +192,12 @@ impl Fragment {
.translate(containing_block.origin.to_vector());
let new_manager = if fragment
.style
- .establishes_containing_block_for_all_descendants()
+ .establishes_containing_block_for_all_descendants(fragment.base.flags)
{
manager.new_for_absolute_and_fixed_descendants(&content_rect, &padding_rect)
} else if fragment
.style
- .establishes_containing_block_for_absolute_descendants()
+ .establishes_containing_block_for_absolute_descendants(fragment.base.flags)
{
manager.new_for_absolute_descendants(&content_rect, &padding_rect)
} else {
diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs
index 024f1ed5399..0b26e8638dd 100644
--- a/components/layout_2020/positioned.rs
+++ b/components/layout_2020/positioned.rs
@@ -18,7 +18,8 @@ use crate::dom::NodeExt;
use crate::dom_traversal::{Contents, NodeAndStyleInfo};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragment_tree::{
- AbsoluteBoxOffsets, BoxFragment, CollapsedBlockMargins, Fragment, HoistedSharedFragment,
+ AbsoluteBoxOffsets, BoxFragment, CollapsedBlockMargins, Fragment, FragmentFlags,
+ HoistedSharedFragment,
};
use crate::geom::{
AuOrAuto, LengthOrAuto, LengthPercentageOrAuto, LogicalRect, LogicalSides, LogicalVec2,
@@ -144,9 +145,13 @@ impl PositioningContext {
}
pub(crate) fn new_for_style(style: &ComputedValues) -> Option<Self> {
- if style.establishes_containing_block_for_all_descendants() {
+ // NB: We never make PositioningContexts for replaced elements, which is why we always
+ // pass false here.
+ if style.establishes_containing_block_for_all_descendants(FragmentFlags::empty()) {
Some(Self::new_for_containing_block_for_all_descendants())
- } else if style.establishes_containing_block_for_absolute_descendants() {
+ } else if style
+ .establishes_containing_block_for_absolute_descendants(FragmentFlags::empty())
+ {
Some(Self {
for_nearest_positioned_ancestor: Some(Vec::new()),
for_nearest_containing_block_for_all_descendants: Vec::new(),
diff --git a/components/layout_2020/style_ext.rs b/components/layout_2020/style_ext.rs
index 243b6bf3083..3430d2ffd8b 100644
--- a/components/layout_2020/style_ext.rs
+++ b/components/layout_2020/style_ext.rs
@@ -20,6 +20,7 @@ use style::Zero;
use webrender_api as wr;
use crate::dom_traversal::Contents;
+use crate::fragment_tree::FragmentFlags;
use crate::geom::{
AuOrAuto, LengthOrAuto, LengthPercentageOrAuto, LogicalSides, LogicalVec2, PhysicalSides,
PhysicalSize,
@@ -179,13 +180,19 @@ pub(crate) trait ComputedValuesExt {
&self,
containing_block_writing_mode: WritingMode,
) -> LogicalSides<LengthPercentageOrAuto<'_>>;
- fn has_transform_or_perspective(&self) -> bool;
+ fn has_transform_or_perspective(&self, fragment_flags: FragmentFlags) -> bool;
fn effective_z_index(&self) -> i32;
fn establishes_block_formatting_context(&self) -> bool;
- fn establishes_stacking_context(&self) -> bool;
+ fn establishes_stacking_context(&self, fragment_flags: FragmentFlags) -> bool;
fn establishes_scroll_container(&self) -> bool;
- fn establishes_containing_block_for_absolute_descendants(&self) -> bool;
- fn establishes_containing_block_for_all_descendants(&self) -> bool;
+ fn establishes_containing_block_for_absolute_descendants(
+ &self,
+ fragment_flags: FragmentFlags,
+ ) -> bool;
+ fn establishes_containing_block_for_all_descendants(
+ &self,
+ fragment_flags: FragmentFlags,
+ ) -> bool;
fn background_is_transparent(&self) -> bool;
fn get_webrender_primitive_flags(&self) -> wr::PrimitiveFlags;
}
@@ -411,7 +418,7 @@ impl ComputedValuesExt for ComputedValues {
/// Returns true if this style has a transform, or perspective property set and
/// it applies to this element.
- fn has_transform_or_perspective(&self) -> bool {
+ fn has_transform_or_perspective(&self, fragment_flags: FragmentFlags) -> bool {
// "A transformable element is an element in one of these categories:
// * all elements whose layout is governed by the CSS box model except for
// non-replaced inline boxes, table-column boxes, and table-column-group
@@ -420,8 +427,9 @@ impl ComputedValuesExt for ComputedValues {
// elements with the exception of any descendant element of text content
// elements."
// https://drafts.csswg.org/css-transforms/#transformable-element
- // FIXME(mrobinson): Properly handle tables and replaced elements here.
- if self.get_box().display.is_inline_flow() {
+ if self.get_box().display.is_inline_flow() &&
+ !fragment_flags.contains(FragmentFlags::IS_REPLACED)
+ {
return false;
}
@@ -464,7 +472,7 @@ impl ComputedValuesExt for ComputedValues {
}
/// Returns true if this fragment establishes a new stacking context and false otherwise.
- fn establishes_stacking_context(&self) -> bool {
+ fn establishes_stacking_context(&self, fragment_flags: FragmentFlags) -> bool {
let effects = self.get_effects();
if effects.opacity != 1.0 {
return true;
@@ -474,7 +482,7 @@ impl ComputedValuesExt for ComputedValues {
return true;
}
- if self.has_transform_or_perspective() {
+ if self.has_transform_or_perspective(fragment_flags) {
return true;
}
@@ -513,8 +521,11 @@ impl ComputedValuesExt for ComputedValues {
/// descendants) this method will return true, but a true return value does
/// not imply that the style establishes a containing block for all descendants.
/// Use `establishes_containing_block_for_all_descendants()` instead.
- fn establishes_containing_block_for_absolute_descendants(&self) -> bool {
- if self.establishes_containing_block_for_all_descendants() {
+ fn establishes_containing_block_for_absolute_descendants(
+ &self,
+ fragment_flags: FragmentFlags,
+ ) -> bool {
+ if self.establishes_containing_block_for_all_descendants(fragment_flags) {
return true;
}
@@ -525,8 +536,11 @@ impl ComputedValuesExt for ComputedValues {
/// all descendants, including fixed descendants (`position: fixed`).
/// Note that this also implies that it establishes a containing block
/// for absolute descendants (`position: absolute`).
- fn establishes_containing_block_for_all_descendants(&self) -> bool {
- if self.has_transform_or_perspective() {
+ fn establishes_containing_block_for_all_descendants(
+ &self,
+ fragment_flags: FragmentFlags,
+ ) -> bool {
+ if self.has_transform_or_perspective(fragment_flags) {
return true;
}
diff --git a/components/layout_2020/table/layout.rs b/components/layout_2020/table/layout.rs
index ea223ea0cce..32531b3c383 100644
--- a/components/layout_2020/table/layout.rs
+++ b/components/layout_2020/table/layout.rs
@@ -22,7 +22,7 @@ use super::{Table, TableSlot, TableSlotCell, TableTrack, TableTrackGroup};
use crate::context::LayoutContext;
use crate::formatting_contexts::{Baselines, IndependentLayout};
use crate::fragment_tree::{
- BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, ExtraBackground, Fragment,
+ BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, ExtraBackground, Fragment, FragmentFlags,
PositioningFragment,
};
use crate::geom::{AuOrAuto, LengthPercentageOrAuto, LogicalRect, LogicalSides, LogicalVec2};
@@ -985,11 +985,15 @@ impl<'a> TableLayout<'a> {
row.group_index.map_or(false, |group_index| {
self.table.row_groups[group_index]
.style
- .establishes_containing_block_for_absolute_descendants()
+ .establishes_containing_block_for_absolute_descendants(
+ FragmentFlags::empty(),
+ )
});
row_group_collects_for_nearest_positioned_ancestor ||
row.style
- .establishes_containing_block_for_absolute_descendants()
+ .establishes_containing_block_for_absolute_descendants(
+ FragmentFlags::empty(),
+ )
});
let mut cells_laid_out_row = Vec::new();