Fix transform assertion failures in Layout 2013 and Layout 2020 (#30713)

Layout asserts that it never creates stacking contexts that have a zero
scale, yet it doesn't prevent the creation of those stacking contexts.
This change stops their creation at an earlier stage.

Fixes #30118.
This commit is contained in:
Martin Robinson 2023-11-13 10:09:25 +01:00 committed by GitHub
parent 1915032f66
commit 72cb34dc3d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 19 additions and 17 deletions

View file

@ -1573,7 +1573,7 @@ impl Fragment {
} }
// If this fragment takes up no space, we don't need to build any display items for it. // If this fragment takes up no space, we don't need to build any display items for it.
if self.has_non_invertible_transform() { if self.has_non_invertible_transform_or_zero_scale() {
return; return;
} }
@ -2419,7 +2419,7 @@ impl BlockFlow {
flags: StackingContextCollectionFlags, flags: StackingContextCollectionFlags,
) { ) {
// This block flow produces no stacking contexts if it takes up no space. // This block flow produces no stacking contexts if it takes up no space.
if self.has_non_invertible_transform() { if self.has_non_invertible_transform_or_zero_scale() {
return; return;
} }

View file

@ -277,7 +277,7 @@ pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static {
might_have_floats_in_or_out might_have_floats_in_or_out
} }
fn has_non_invertible_transform(&self) -> bool { fn has_non_invertible_transform_or_zero_scale(&self) -> bool {
if !self.class().is_block_like() || if !self.class().is_block_like() ||
self.as_block() self.as_block()
.fragment .fragment
@ -290,7 +290,9 @@ pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static {
return false; return false;
} }
self.as_block().fragment.has_non_invertible_transform() self.as_block()
.fragment
.has_non_invertible_transform_or_zero_scale()
} }
fn get_overflow_in_parent_coordinates(&self) -> Overflow { fn get_overflow_in_parent_coordinates(&self) -> Overflow {
@ -1176,7 +1178,7 @@ impl BaseFlow {
state: &mut StackingContextCollectionState, state: &mut StackingContextCollectionState,
) { ) {
for kid in self.children.iter_mut() { for kid in self.children.iter_mut() {
if !kid.has_non_invertible_transform() { if !kid.has_non_invertible_transform_or_zero_scale() {
kid.collect_stacking_contexts(state); kid.collect_stacking_contexts(state);
} }
} }

View file

@ -2760,9 +2760,11 @@ impl Fragment {
} }
/// Returns true if this fragment has a transform applied that causes it to take up no space. /// Returns true if this fragment has a transform applied that causes it to take up no space.
pub fn has_non_invertible_transform(&self) -> bool { pub fn has_non_invertible_transform_or_zero_scale(&self) -> bool {
self.transform_matrix(&Rect::default()) self.transform_matrix(&Rect::default())
.map_or(false, |matrix| !matrix.is_invertible()) .map_or(false, |matrix| {
!matrix.is_invertible() || matrix.m11 == 0. || matrix.m22 == 0.
})
} }
/// Returns true if this fragment establishes a new stacking context and false otherwise. /// Returns true if this fragment establishes a new stacking context and false otherwise.

View file

@ -1882,7 +1882,7 @@ impl Flow for InlineFlow {
for fragment in self.fragments.fragments.iter_mut() { for fragment in self.fragments.fragments.iter_mut() {
// If a particular fragment would establish a stacking context but has a transform // If a particular fragment would establish a stacking context but has a transform
// applied that causes it to take up no space, we can skip it entirely. // applied that causes it to take up no space, we can skip it entirely.
if fragment.has_non_invertible_transform() { if fragment.has_non_invertible_transform_or_zero_scale() {
continue; continue;
} }
state.containing_block_clipping_and_scrolling = previous_cb_clipping_and_scrolling; state.containing_block_clipping_and_scrolling = previous_cb_clipping_and_scrolling;

View file

@ -345,7 +345,7 @@ pub struct BuildDisplayList<'a> {
impl<'a> BuildDisplayList<'a> { impl<'a> BuildDisplayList<'a> {
#[inline] #[inline]
pub fn traverse(&mut self, flow: &mut dyn Flow) { pub fn traverse(&mut self, flow: &mut dyn Flow) {
if flow.has_non_invertible_transform() { if flow.has_non_invertible_transform_or_zero_scale() {
return; return;
} }

View file

@ -787,8 +787,10 @@ impl Fragment {
// If this fragment has a transform applied that makes it take up no space // If this fragment has a transform applied that makes it take up no space
// then we don't need to create any stacking contexts for it. // then we don't need to create any stacking contexts for it.
let has_non_invertible_transform = let has_non_invertible_transform = fragment
fragment.has_non_invertible_transform(&containing_block.rect.to_untyped()); .has_non_invertible_transform_or_zero_scale(
&containing_block.rect.to_untyped(),
);
if has_non_invertible_transform { if has_non_invertible_transform {
return; return;
} }
@ -1258,10 +1260,10 @@ impl BoxFragment {
} }
/// Returns true if the given style contains a transform that is not invertible. /// Returns true if the given style contains a transform that is not invertible.
fn has_non_invertible_transform(&self, containing_block: &Rect<Length>) -> bool { fn has_non_invertible_transform_or_zero_scale(&self, containing_block: &Rect<Length>) -> bool {
let list = &self.style.get_box().transform; let list = &self.style.get_box().transform;
match list.to_transform_3d_matrix(Some(containing_block)) { match list.to_transform_3d_matrix(Some(containing_block)) {
Ok(t) => !t.0.is_invertible(), Ok(t) => !t.0.is_invertible() || t.0.m11 == 0. || t.0.m22 == 0.,
Err(_) => false, Err(_) => false,
} }
} }

View file

@ -1,2 +0,0 @@
[preserve3d-scene-001.html]
expected: CRASH

View file

@ -1,2 +0,0 @@
[preserve3d-scene-002.html]
expected: CRASH