diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 0e39e74c4618..70c02ffdab15 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -1400,28 +1400,36 @@ nsLayoutUtils::InvalidateForDisplayPortChange(nsIContent* aContent, // rect properties on so we can find the frame later to remove the properties. frame->SchedulePaint(); + if (!gfxPrefs::LayoutRetainDisplayList()) { + return; + } + nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(frame); RetainedDisplayListBuilder* retainedBuilder = displayRoot->GetProperty(RetainedDisplayListBuilder::Cached()); - if (retainedBuilder) { - nsRect* rect = - frame->GetProperty(nsDisplayListBuilder::DisplayListBuildingDisplayPortRect()); - if (!rect) { - rect = new nsRect(); - frame->SetProperty(nsDisplayListBuilder::DisplayListBuildingDisplayPortRect(), rect); - frame->SetHasOverrideDirtyRegion(true); - } - if (aHadDisplayPort) { - // We only need to build a display list for any new areas added - nsRegion newRegion(aNewDisplayPort); - newRegion.SubOut(aOldDisplayPort); - rect->UnionRect(*rect, newRegion.GetBounds()); - } else { - rect->UnionRect(*rect, aNewDisplayPort); - } + + if (!retainedBuilder) { + return; + } + + nsRect* rect = + frame->GetProperty(nsDisplayListBuilder::DisplayListBuildingDisplayPortRect()); + + if (!rect) { + rect = new nsRect(); + frame->SetProperty(nsDisplayListBuilder::DisplayListBuildingDisplayPortRect(), rect); + frame->SetHasOverrideDirtyRegion(true); + } + + if (aHadDisplayPort) { + // We only need to build a display list for any new areas added + nsRegion newRegion(aNewDisplayPort); + newRegion.SubOut(aOldDisplayPort); + rect->UnionRect(*rect, newRegion.GetBounds()); + } else { + rect->UnionRect(*rect, aNewDisplayPort); } } - } bool diff --git a/layout/painting/RetainedDisplayListBuilder.cpp b/layout/painting/RetainedDisplayListBuilder.cpp index 89876a59a4ef..5207f6b6606e 100644 --- a/layout/painting/RetainedDisplayListBuilder.cpp +++ b/layout/painting/RetainedDisplayListBuilder.cpp @@ -760,6 +760,20 @@ ShouldBuildPartial(nsTArray& aModifiedFrames) return true; } +static void +ClearFrameProps(nsTArray& aFrames) +{ + for (nsIFrame* f : aFrames) { + if (f->HasOverrideDirtyRegion()) { + f->SetHasOverrideDirtyRegion(false); + f->DeleteProperty(nsDisplayListBuilder::DisplayListBuildingRect()); + f->DeleteProperty(nsDisplayListBuilder::DisplayListBuildingDisplayPortRect()); + } + + f->SetFrameIsModified(false); + } +} + bool RetainedDisplayListBuilder::AttemptPartialUpdate(nscolor aBackstop) { @@ -773,7 +787,10 @@ RetainedDisplayListBuilder::AttemptPartialUpdate(nscolor aBackstop) nsTArray modifiedFrames = GetModifiedFrames(mBuilder.RootReferenceFrame()); - const bool shouldBuildPartial = ShouldBuildPartial(modifiedFrames); + // Do not allow partial builds if the retained display list is empty, or if + // ShouldBuildPartial heuristic fails. + const bool shouldBuildPartial = + !mList.IsEmpty() && ShouldBuildPartial(modifiedFrames); if (mPreviousCaret != mBuilder.GetCaretFrame()) { if (mPreviousCaret) { @@ -795,8 +812,9 @@ RetainedDisplayListBuilder::AttemptPartialUpdate(nscolor aBackstop) AnimatedGeometryRoot* modifiedAGR = nullptr; nsTArray framesWithProps; bool merged = false; - if (shouldBuildPartial && !mList.IsEmpty() && - ComputeRebuildRegion(modifiedFrames, &modifiedDirty, &modifiedAGR, &framesWithProps)) { + if (shouldBuildPartial && + ComputeRebuildRegion(modifiedFrames, &modifiedDirty, + &modifiedAGR, &framesWithProps)) { modifiedDirty.IntersectRect(modifiedDirty, mBuilder.RootReferenceFrame()->GetVisualOverflowRectRelativeToSelf()); PreProcessDisplayList(&mList, modifiedAGR); @@ -838,21 +856,11 @@ RetainedDisplayListBuilder::AttemptPartialUpdate(nscolor aBackstop) mBuilder.LeavePresShell(mBuilder.RootReferenceFrame(), &mList); - // TODO: Do we mark frames as modified during displaylist building? If - // we do this isn't gonna work. - for (nsIFrame* f : modifiedFrames) { - if (f) { - f->SetFrameIsModified(false); - } - } - - // Override dirty regions should only exist during this function. We set them up during - // ComputeRebuildRegion, and clear them here. - for (nsIFrame* f: framesWithProps) { - f->SetHasOverrideDirtyRegion(false); - f->DeleteProperty(nsDisplayListBuilder::DisplayListBuildingRect()); - f->DeleteProperty(nsDisplayListBuilder::DisplayListBuildingDisplayPortRect()); - } + // We set the override dirty regions during ComputeRebuildRegion or in + // nsLayoutUtils::InvalidateForDisplayPortChange. The display port change also + // marks the frame modified, so those regions are cleared here as well. + ClearFrameProps(modifiedFrames); + ClearFrameProps(framesWithProps); return merged; }