From 10a44a77176eb1a30dabb4d0fc212c75219e60f1 Mon Sep 17 00:00:00 2001 From: Miko Mynttinen Date: Fri, 12 Jan 2018 18:02:14 +0100 Subject: [PATCH] Bug 1428993 - Part 2: Override dirty rect for stacking contexts between OOF frame placeholder and the containing block r=mattwoodrow MozReview-Commit-ID: FoX9uyoiqj4 --HG-- extra : rebase_source : 08d1aad9ec618bfccf95ba4983cb57aaaeb82070 --- layout/base/nsLayoutUtils.cpp | 4 +- layout/generic/nsFrame.cpp | 5 + .../painting/RetainedDisplayListBuilder.cpp | 120 ++++++++++++------ .../reftests/display-list/1428993-1-ref.html | 25 ++++ layout/reftests/display-list/1428993-1.html | 61 +++++++++ .../reftests/display-list/1428993-2-ref.html | 34 +++++ layout/reftests/display-list/1428993-2.html | 62 +++++++++ layout/reftests/display-list/reftest.list | 2 + 8 files changed, 275 insertions(+), 38 deletions(-) create mode 100644 layout/reftests/display-list/1428993-1-ref.html create mode 100644 layout/reftests/display-list/1428993-1.html create mode 100644 layout/reftests/display-list/1428993-2-ref.html create mode 100644 layout/reftests/display-list/1428993-2.html diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 21d704a31be1..d5b96386c7cf 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -2707,7 +2707,9 @@ nsLayoutUtils::GetTransformToAncestor(nsIFrame *aFrame, ctm = aFrame->GetTransformMatrix(aAncestor, &parent, aFlags); while (parent && parent != aAncestor && (!(aFlags & nsIFrame::STOP_AT_STACKING_CONTEXT_AND_DISPLAY_PORT) || - (!parent->IsStackingContext() && !FrameHasDisplayPort(parent)))) { + (!parent->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) && + !parent->IsStackingContext() && + !FrameHasDisplayPort(parent)))) { if (!parent->Extend3DContext()) { ctm.ProjectTo2D(); } diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index c29320bd3054..54b6f9d19e97 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -1019,6 +1019,11 @@ nsIFrame::MarkNeedsDisplayItemRebuild() return; } + if (Type() == LayoutFrameType::Placeholder) { + // Do not mark placeholder frames modified. + return; + } + nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(this); MOZ_ASSERT(displayRoot); diff --git a/layout/painting/RetainedDisplayListBuilder.cpp b/layout/painting/RetainedDisplayListBuilder.cpp index becb5a8c0328..f77de697e7db 100644 --- a/layout/painting/RetainedDisplayListBuilder.cpp +++ b/layout/painting/RetainedDisplayListBuilder.cpp @@ -6,6 +6,7 @@ */ #include "RetainedDisplayListBuilder.h" +#include "nsPlaceholderFrame.h" #include "nsSubDocumentFrame.h" #include "nsViewManager.h" @@ -624,7 +625,7 @@ static void ProcessFrame(nsIFrame* aFrame, nsDisplayListBuilder& aBuilder, AnimatedGeometryRoot** aAGR, nsRect& aOverflow, nsIFrame* aStopAtFrame, nsTArray& aOutFramesWithProps, - const bool /* aStopAtStackingContext */) + const bool aStopAtStackingContext) { nsIFrame* currentFrame = aFrame; @@ -633,13 +634,47 @@ ProcessFrame(nsIFrame* aFrame, nsDisplayListBuilder& aBuilder, // Convert 'aOverflow' into the coordinate space of the nearest stacking context // or display port ancestor and update 'currentFrame' to point to that frame. - aOverflow = nsLayoutUtils::TransformFrameRectToAncestor(currentFrame, aOverflow, - aStopAtFrame, - nullptr, nullptr, - /* aStopAtStackingContextAndDisplayPort = */ true, - ¤tFrame); + nsIFrame* previousFrame = currentFrame; + aOverflow = nsLayoutUtils::TransformFrameRectToAncestor(currentFrame, aOverflow, aStopAtFrame, + nullptr, nullptr, + /* aStopAtStackingContextAndDisplayPortAndOOFFrame = */ true, + ¤tFrame); MOZ_ASSERT(currentFrame); + // If the current frame is an OOF frame, DisplayListBuildingData needs to be + // set on all the ancestor stacking contexts of the placeholder frame, up + // to the containing block of the OOF frame. This is done to ensure that the + // content that might be behind the OOF frame is built for merging. + nsIFrame* placeholder = previousFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) + ? previousFrame->GetPlaceholderFrame() + : nullptr; + + if (placeholder) { + nsRect placeholderOverflow = + aOverflow + previousFrame->GetOffsetTo(placeholder); + + CRR_LOG("Processing placeholder %p for OOF frame %p\n", + placeholder, previousFrame); + + CRR_LOG("OOF frame draw area: %d %d %d %d\n", + placeholderOverflow.x, placeholderOverflow.y, + placeholderOverflow.width, placeholderOverflow.height); + + // Tracking AGRs for the placeholder processing is not necessary, as the + // goal is to only modify the DisplayListBuildingData rect. + AnimatedGeometryRoot* dummyAGR = nullptr; + + // Find a common ancestor frame to handle frame continuations. + // TODO: It might be possible to write a more specific and efficient + // function for this. + nsIFrame* ancestor = + nsLayoutUtils::FindNearestCommonAncestorFrame(previousFrame->GetParent(), + placeholder->GetParent()); + + ProcessFrame(placeholder, aBuilder, &dummyAGR, placeholderOverflow, + ancestor, aOutFramesWithProps, false); + } + if (nsLayoutUtils::FrameHasDisplayPort(currentFrame)) { CRR_LOG("Frame belongs to displayport frame %p\n", currentFrame); nsIScrollableFrame* sf = do_QueryFrame(currentFrame); @@ -662,7 +697,8 @@ ProcessFrame(nsIFrame* aFrame, nsDisplayListBuilder& aBuilder, aOutFramesWithProps.AppendElement(currentFrame); } rect->UnionRect(*rect, r); - CRR_LOG("Adding area to displayport draw area: %d %d %d %d\n", r.x, r.y, r.width, r.height); + CRR_LOG("Adding area to displayport draw area: %d %d %d %d\n", + r.x, r.y, r.width, r.height); // TODO: Can we just use MarkFrameForDisplayIfVisible, plus MarkFramesForDifferentAGR to // ensure that this displayport, plus any items that move relative to it get rebuilt, @@ -680,40 +716,50 @@ ProcessFrame(nsIFrame* aFrame, nsDisplayListBuilder& aBuilder, // If we found an intermediate stacking context with an existing display item // then we can store the dirty rect there and stop. If we couldn't find one then // we need to keep bubbling up to the next stacking context. - if (currentFrame != aBuilder.RootReferenceFrame() && - currentFrame->HasDisplayItems()) { - aBuilder.MarkFrameForDisplayIfVisible(currentFrame, - aBuilder.RootReferenceFrame()); - - // Store the stacking context relative dirty area such - // that display list building will pick it up when it - // gets to it. - nsDisplayListBuilder::DisplayListBuildingData* data = - currentFrame->GetProperty(nsDisplayListBuilder::DisplayListBuildingRect()); - if (!data) { - data = new nsDisplayListBuilder::DisplayListBuildingData; - currentFrame->SetProperty(nsDisplayListBuilder::DisplayListBuildingRect(), data); - currentFrame->SetHasOverrideDirtyRegion(true); - aOutFramesWithProps.AppendElement(currentFrame); - } - data->mDirtyRect.UnionRect(data->mDirtyRect, aOverflow); - CRR_LOG("Adding area to stacking context draw area: %d %d %d %d\n", - aOverflow.x, aOverflow.y, aOverflow.width, aOverflow.height); - if (!data->mModifiedAGR) { - data->mModifiedAGR = *aAGR; - } else if (data->mModifiedAGR != *aAGR) { - data->mDirtyRect = currentFrame->GetVisualOverflowRectRelativeToSelf(); - CRR_LOG("Found multiple modified AGRs within this stacking context, giving up\n"); - } - - // Don't contribute to the root dirty area at all. - *aAGR = nullptr; - aOverflow.SetEmpty(); - break; + if (currentFrame == aBuilder.RootReferenceFrame() || + !currentFrame->HasDisplayItems()) { + continue; } + + aBuilder.MarkFrameForDisplayIfVisible(currentFrame, + aBuilder.RootReferenceFrame()); + + // Store the stacking context relative dirty area such + // that display list building will pick it up when it + // gets to it. + nsDisplayListBuilder::DisplayListBuildingData* data = + currentFrame->GetProperty(nsDisplayListBuilder::DisplayListBuildingRect()); + if (!data) { + data = new nsDisplayListBuilder::DisplayListBuildingData(); + currentFrame->SetProperty(nsDisplayListBuilder::DisplayListBuildingRect(), data); + currentFrame->SetHasOverrideDirtyRegion(true); + aOutFramesWithProps.AppendElement(currentFrame); + } + CRR_LOG("Adding area to stacking context draw area: %d %d %d %d\n", + aOverflow.x, aOverflow.y, aOverflow.width, aOverflow.height); + data->mDirtyRect.UnionRect(data->mDirtyRect, aOverflow); + + if (!aStopAtStackingContext) { + // Continue ascending the frame tree until we reach aStopAtFrame. + continue; + } + + if (!data->mModifiedAGR) { + data->mModifiedAGR = *aAGR; + } else if (data->mModifiedAGR != *aAGR) { + data->mDirtyRect = currentFrame->GetVisualOverflowRectRelativeToSelf(); + CRR_LOG("Found multiple modified AGRs within this stacking context, giving up\n"); + } + + // Don't contribute to the root dirty area at all. + aOverflow.SetEmpty(); + *aAGR = nullptr; + + break; } } } + /** * Given a list of frames that has been modified, computes the region that we need to * do display list building for in order to build all modified display items. diff --git a/layout/reftests/display-list/1428993-1-ref.html b/layout/reftests/display-list/1428993-1-ref.html new file mode 100644 index 000000000000..d04ab0273b42 --- /dev/null +++ b/layout/reftests/display-list/1428993-1-ref.html @@ -0,0 +1,25 @@ + + + + + +Retained display list test + + + + +
+
+ + diff --git a/layout/reftests/display-list/1428993-1.html b/layout/reftests/display-list/1428993-1.html new file mode 100644 index 000000000000..058cb676614a --- /dev/null +++ b/layout/reftests/display-list/1428993-1.html @@ -0,0 +1,61 @@ + + + + + +Retained display list test + + + + +
+
+ +
+ + + + diff --git a/layout/reftests/display-list/1428993-2-ref.html b/layout/reftests/display-list/1428993-2-ref.html new file mode 100644 index 000000000000..a5ed24618f8a --- /dev/null +++ b/layout/reftests/display-list/1428993-2-ref.html @@ -0,0 +1,34 @@ + + + + + +Retained display list test + + + + +
+
+
+ + diff --git a/layout/reftests/display-list/1428993-2.html b/layout/reftests/display-list/1428993-2.html new file mode 100644 index 000000000000..24515231bc5d --- /dev/null +++ b/layout/reftests/display-list/1428993-2.html @@ -0,0 +1,62 @@ + + + + + +Retained display list test + + + + +
+
+
+
+
+
+ + + diff --git a/layout/reftests/display-list/reftest.list b/layout/reftests/display-list/reftest.list index 63b40e7e2c4e..5b68cfae1cac 100644 --- a/layout/reftests/display-list/reftest.list +++ b/layout/reftests/display-list/reftest.list @@ -12,3 +12,5 @@ fuzzy(1,235200) == 1413073.html 1413073-ref.html == 1416291.html 1416291-ref.html == 1417601-1.html 1417601-1-ref.html == 1418945-1.html 1418945-1-ref.html +== 1428993-1.html 1428993-1-ref.html +== 1428993-2.html 1428993-2-ref.html