diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index ddf2e73e9b20..866b74fbd8f2 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -5098,6 +5098,36 @@ nsRect nsDisplayTransform::TransformRectOut(const nsRect &aUntransformedBounds, factor); } +bool nsDisplayTransform::UntransformRect(const nsRect &aTransformedBounds, + const nsRect &aChildBounds, + const nsIFrame* aFrame, + const nsPoint &aOrigin, + nsRect *aOutRect) +{ + NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!"); + + float factor = aFrame->PresContext()->AppUnitsPerDevPixel(); + + gfx3DMatrix transform = GetResultingTransformMatrix(aFrame, aOrigin, factor, nullptr); + if (transform.IsSingular()) { + return false; + } + + gfxRect result(NSAppUnitsToFloatPixels(aTransformedBounds.x, factor), + NSAppUnitsToFloatPixels(aTransformedBounds.y, factor), + NSAppUnitsToFloatPixels(aTransformedBounds.width, factor), + NSAppUnitsToFloatPixels(aTransformedBounds.height, factor)); + + gfxRect childGfxBounds(NSAppUnitsToFloatPixels(aChildBounds.x, factor), + NSAppUnitsToFloatPixels(aChildBounds.y, factor), + NSAppUnitsToFloatPixels(aChildBounds.width, factor), + NSAppUnitsToFloatPixels(aChildBounds.height, factor)); + + result = transform.UntransformBounds(result, childGfxBounds); + *aOutRect = nsLayoutUtils::RoundGfxRectToAppRect(result, factor); + return true; +} + bool nsDisplayTransform::UntransformVisibleRect(nsDisplayListBuilder* aBuilder, nsRect *aOutRect) { diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 7842d4dbe7f7..6cafad162bdb 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -3258,6 +3258,12 @@ public: /* UntransformRect is like TransformRect, except that it inverts the * transform. */ + static bool UntransformRect(const nsRect &aTransformedBounds, + const nsRect &aChildBounds, + const nsIFrame* aFrame, + const nsPoint &aOrigin, + nsRect *aOutRect); + bool UntransformVisibleRect(nsDisplayListBuilder* aBuilder, nsRect* aOutRect); diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 536921a7776a..269bbe0947e3 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -1929,22 +1929,16 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, if (overflow.IsEmpty() && !Preserves3DChildren()) { return; } - // Trying to back-transform arbitrary rects gives us really weird results. I believe - // this is from points that lie beyond the vanishing point. As a workaround we transform - // the overflow rect into screen space and compare in that coordinate system. - // Transform the overflow rect into screen space. nsPoint offset = aBuilder->ToReferenceFrame(this); - nsRect trans = nsDisplayTransform::TransformRect(overflow + offset, this, offset); dirtyRect += offset; - if (dirtyRect.Intersects(trans)) { - // If they intersect, we take our whole overflow rect. We could instead take the intersection - // and then reverse transform it but I doubt this extra work is worthwhile. - dirtyRect = overflow; + + nsRect untransformedDirtyRect; + if (nsDisplayTransform::UntransformRect(dirtyRect, overflow, this, offset, &untransformedDirtyRect)) { + dirtyRect = untransformedDirtyRect; } else { - if (!Preserves3DChildren()) { - return; - } + NS_WARNING("Unable to untransform dirty rect!"); + // This should only happen if the transform is singular, in which case nothing is visible anyway dirtyRect.SetEmpty(); } }