diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 9469ac64170a..8d07a8522562 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -1604,7 +1604,7 @@ bool nsIFrame::Combines3DTransformWithAncestors(const nsStyleDisplay* aStyleDisplay) const { MOZ_ASSERT(aStyleDisplay == StyleDisplay()); - nsIFrame* parent = GetInFlowParent(); + nsIFrame* parent = GetClosestFlattenedTreeAncestorPrimaryFrame(); if (!parent || !parent->Extend3DContext()) { return false; } @@ -2625,9 +2625,9 @@ FrameParticipatesIn3DContext(nsIFrame* aAncestor, nsIFrame* aDescendant) { MOZ_ASSERT(aAncestor != aDescendant); MOZ_ASSERT(aAncestor->Extend3DContext()); nsIFrame* frame; - for (frame = aDescendant->GetInFlowParent(); + for (frame = aDescendant->GetClosestFlattenedTreeAncestorPrimaryFrame(); frame && aAncestor != frame; - frame = frame->GetInFlowParent()) { + frame = frame->GetClosestFlattenedTreeAncestorPrimaryFrame()) { if (!frame->Extend3DContext()) { return false; } diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 27d70cd771be..4e9641f042cf 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -867,13 +867,16 @@ public: /** * Gets the parent of a frame, using the parent of the placeholder for * out-of-flow frames. - * - * This is effectively the primary frame (or one of the continuations) of the - * closest flattened tree ancestor that has a frame (flattened tree ancestors - * may not have frames in presence of display: contents). */ inline nsContainerFrame* GetInFlowParent() const; + /** + * Gets the primary frame of the closest flattened tree ancestor that has a + * frame (flattened tree ancestors may not have frames in presence of display: + * contents). + */ + inline nsIFrame* GetClosestFlattenedTreeAncestorPrimaryFrame() const; + /** * Return the placeholder for this frame (which must be out-of-flow). * @note this will only return non-null if |this| is the first-in-flow diff --git a/layout/generic/nsIFrameInlines.h b/layout/generic/nsIFrameInlines.h index 5a00479f759b..566e04b20173 100644 --- a/layout/generic/nsIFrameInlines.h +++ b/layout/generic/nsIFrameInlines.h @@ -7,6 +7,7 @@ #ifndef nsIFrameInlines_h___ #define nsIFrameInlines_h___ +#include "mozilla/dom/ElementInlines.h" #include "nsContainerFrame.h" #include "nsPlaceholderFrame.h" #include "nsStyleStructInlines.h" @@ -180,4 +181,42 @@ nsIFrame::GetInFlowParent() const return GetParent(); } +// We generally want to follow the style tree for preserve-3d, jumping through +// display: contents. +// +// There are various fun mismatches between the flattened tree and the frame +// tree which makes this non-trivial to do looking at the frame tree state: +// +// - Anon boxes. You'd have to step through them, because you generally want to +// ignore them. +// +// - IB-splits, which produce a frame tree where frames for the block inside +// the inline are not children of any frame from the inline. +// +// - display: contents, which makes DOM ancestors not have frames even when a +// descendant does. +// +// See GetFlattenedTreeParentElementForStyle for the difference between it and +// plain GetFlattenedTreeParentElement. +nsIFrame* +nsIFrame::GetClosestFlattenedTreeAncestorPrimaryFrame() const +{ + if (!mContent) { + return nullptr; + } + Element* parent = mContent->GetFlattenedTreeParentElementForStyle(); + while (parent) { + if (nsIFrame* frame = parent->GetPrimaryFrame()) { + return frame; + } + // NOTE(emilio): This should be an assert except we have code in tree which + // violates invariants like the frame construction code. + if (MOZ_UNLIKELY(!parent->IsDisplayContents())) { + return nullptr; + } + parent = parent->GetFlattenedTreeParentElementForStyle(); + } + return nullptr; +} + #endif diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp index 1d5408a0e067..c7c3ba939890 100644 --- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -8377,7 +8377,7 @@ nsDisplayTransform::GetResultingTransformMatrixInternal( if ((aFlags & INCLUDE_PRESERVE3D_ANCESTORS) && frame && frame->Combines3DTransformWithAncestors()) { // Include the transform set on our parent - nsIFrame* parentFrame = frame->GetInFlowParent(); + nsIFrame* parentFrame = frame->GetClosestFlattenedTreeAncestorPrimaryFrame(); NS_ASSERTION(parentFrame && parentFrame->IsTransformed() && parentFrame->Extend3DContext(), "Preserve3D mismatch!"); @@ -8656,7 +8656,7 @@ nsDisplayTransform::GetAccumulatedPreserved3DTransform( const nsIFrame* establisher; // Establisher of the 3D rendering context. for (establisher = mFrame; establisher && establisher->Combines3DTransformWithAncestors(); - establisher = establisher->GetInFlowParent()) { + establisher = establisher->GetClosestFlattenedTreeAncestorPrimaryFrame()) { } const nsIFrame* establisherReference = aBuilder->FindReferenceFrameFor( nsLayoutUtils::GetCrossDocParentFrame(establisher)); diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index 652e6da8c31c..d5f2435e0992 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -143185,6 +143185,18 @@ {} ] ], + "css/css-transforms/preserve3d-button.html": [ + [ + "/css/css-transforms/preserve3d-button.html", + [ + [ + "/css/css-transforms/preserve3d-button-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-transforms/rotate/svg-rotate-3args-001.html": [ [ "/css/css-transforms/rotate/svg-rotate-3args-001.html", @@ -265202,6 +265214,11 @@ {} ] ], + "css/css-transforms/preserve3d-button-ref.html": [ + [ + {} + ] + ], "css/css-transforms/reference/backface-visibility-hidden-ref.html": [ [ {} @@ -561880,6 +561897,14 @@ "752888eaf76630ae9835dd444c4941793ecf53cc", "reftest" ], + "css/css-transforms/preserve3d-button-ref.html": [ + "e5e3c1ebfcdd7c832a211d17ac2f1ed6f4116252", + "support" + ], + "css/css-transforms/preserve3d-button.html": [ + "544bb2496638a52915f7c97a238ccb053b4e884e", + "reftest" + ], "css/css-transforms/reference/backface-visibility-hidden-ref.html": [ "6a3e305e5c0c7fca6c8d53574b7a09eb21afb6cc", "support" @@ -578401,7 +578426,7 @@ "testharness" ], "css/cssom/overflow-serialization.html": [ - "2911c8da3e3ae47af4fd764170fd7439cda56685", + "136b8aba117eb64403700d8c4348db085cede9c8", "testharness" ], "css/cssom/preferred-stylesheet-order.html": [ @@ -578793,7 +578818,7 @@ "reftest" ], "css/filter-effects/filter-cb-abspos-inline-001-ref.html": [ - "6ebe4635511242cd0f5965a778a5a491cc406436", + "b4beae8004155c30dad4f48db3e2087f66c42c4f", "support" ], "css/filter-effects/filter-cb-abspos-inline-001.html": [ diff --git a/testing/web-platform/tests/css/css-transforms/preserve3d-button-ref.html b/testing/web-platform/tests/css/css-transforms/preserve3d-button-ref.html new file mode 100644 index 000000000000..e5e3c1ebfcdd --- /dev/null +++ b/testing/web-platform/tests/css/css-transforms/preserve3d-button-ref.html @@ -0,0 +1,42 @@ + +CSS Test Reference + + + +
+
+
+
+
+
diff --git a/testing/web-platform/tests/css/css-transforms/preserve3d-button.html b/testing/web-platform/tests/css/css-transforms/preserve3d-button.html new file mode 100644 index 000000000000..544bb2496638 --- /dev/null +++ b/testing/web-platform/tests/css/css-transforms/preserve3d-button.html @@ -0,0 +1,44 @@ + +CSS Test: preserve-3d on buttons + + + + + +
+ +