Bug 1404181 - Part 20: Add code to override the display list builder dirty area for a stacking context or displayport. This lets us restrict partial building to within one of these contexts. r?mstange
MozReview-Commit-ID: Dn46eaqeyPX
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -2607,16 +2607,25 @@ nsIFrame::BuildDisplayListForStackingCon
// This should only happen if the transform is singular, in which case nothing is visible anyway
dirtyRect.SetEmpty();
visibleRect.SetEmpty();
}
}
inTransform = true;
}
+ bool hasOverrideDirtyRect = false;
+ if (HasOverrideDirtyRegion() && !aBuilder->InInvalidSubtree()) {
+ nsDisplayListBuilder::DisplayListBuildingData* data =
+ GetProperty(nsDisplayListBuilder::DisplayListBuildingRect());
+ if (data) {
+ dirtyRect = data->mDirtyRect.Intersect(visibleRect);
+ hasOverrideDirtyRect = true;
+ }
+ }
bool usingFilter = StyleEffects()->HasFilters();
bool usingMask = nsSVGIntegrationUtils::UsingMaskOrClipPathForFrame(this);
bool usingSVGEffects = usingFilter || usingMask;
nsRect visibleRectOutsideSVGEffects = visibleRect;
nsDisplayList hoistedScrollInfoItemsStorage(aBuilder);
if (usingSVGEffects) {
dirtyRect =
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3315,19 +3315,19 @@ ScrollFrameHelper::BuildDisplayList(nsDi
// dirty rect here.
nsRect visibleRect = aBuilder->GetVisibleRect();
nsRect dirtyRect = aBuilder->GetDirtyRect();
if (!ignoringThisScrollFrame) {
visibleRect = visibleRect.Intersect(mScrollPort);
dirtyRect = dirtyRect.Intersect(mScrollPort);
}
- bool usingDisplayPortInvalidRect = false;
+ bool dirtyRectHasBeenOverriden = false;
Unused << DecideScrollableLayer(aBuilder, &visibleRect, &dirtyRect,
- /* aSetBase = */ !mIsRoot);
+ /* aSetBase = */ !mIsRoot, &dirtyRectHasBeenOverriden);
if (aBuilder->IsForFrameVisibility()) {
// We expand the dirty rect to catch frames just outside of the scroll port.
// We use the dirty rect instead of the whole scroll port to prevent
// too much expansion in the presence of very large (bigger than the
// viewport) scroll ports.
dirtyRect = ExpandRectToNearlyVisible(dirtyRect);
visibleRect = dirtyRect;
@@ -3588,17 +3588,17 @@ ScrollFrameHelper::BuildDisplayList(nsDi
0,
nsLayoutUtils::RepaintMode::DoNotRepaint);
// Call DecideScrollableLayer to recompute mWillBuildScrollableLayer and
// recompute the current animated geometry root if needed.
// It's too late to change the dirty rect so pass a copy.
nsRect copyOfDirtyRect = dirtyRect;
nsRect copyOfVisibleRect = visibleRect;
Unused << DecideScrollableLayer(aBuilder, ©OfVisibleRect, ©OfDirtyRect,
- /* aSetBase = */ false);
+ /* aSetBase = */ false, nullptr);
if (mWillBuildScrollableLayer) {
asrSetter.InsertScrollFrame(sf);
}
}
}
}
if (mWillBuildScrollableLayer && aBuilder->IsPaintingToWindow()) {
@@ -3634,17 +3634,18 @@ ScrollFrameHelper::BuildDisplayList(nsDi
scrolledContent.MoveTo(aLists);
}
bool
ScrollFrameHelper::DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
nsRect* aVisibleRect,
nsRect* aDirtyRect,
- bool aSetBase)
+ bool aSetBase,
+ bool* aDirtyRectHasBeenOverriden)
{
// Save and check if this changes so we can recompute the current agr.
bool oldWillBuildScrollableLayer = mWillBuildScrollableLayer;
nsIContent* content = mOuter->GetContent();
bool usingDisplayPort = nsLayoutUtils::HasDisplayPort(content);
if (aBuilder->IsPaintingToWindow()) {
if (aSetBase) {
@@ -3740,17 +3741,31 @@ ScrollFrameHelper::DecideScrollableLayer
MOZ_ASSERT(content->GetProperty(nsGkAtoms::DisplayPortBase));
nsRect displayPort;
usingDisplayPort =
nsLayoutUtils::GetDisplayPort(content, &displayPort, RelativeTo::ScrollFrame);
if (usingDisplayPort) {
// Override the dirty rectangle if the displayport has been set.
*aVisibleRect = displayPort;
- *aDirtyRect = displayPort;
+ if (!aBuilder->IsPartialUpdate() || aBuilder->InInvalidSubtree()) {
+ *aDirtyRect = displayPort;
+ if (aDirtyRectHasBeenOverriden) {
+ *aDirtyRectHasBeenOverriden = true;
+ }
+ } else if (mOuter->HasOverrideDirtyRegion()) {
+ nsRect* rect =
+ mOuter->GetProperty(nsDisplayListBuilder::DisplayListBuildingDisplayPortRect());
+ if (rect) {
+ *aDirtyRect = *rect;
+ if (aDirtyRectHasBeenOverriden) {
+ *aDirtyRectHasBeenOverriden = true;
+ }
+ }
+ }
} else if (mIsRoot) {
// The displayPort getter takes care of adjusting for resolution. So if
// we have resolution but no displayPort then we need to adjust for
// resolution here.
nsIPresShell* presShell = mOuter->PresContext()->PresShell();
*aVisibleRect = aVisibleRect->RemoveResolution(
presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f);
*aDirtyRect = aDirtyRect->RemoveResolution(
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -411,17 +411,18 @@ public:
bool UsesContainerScrolling() const;
ScrollSnapInfo GetScrollSnapInfo() const;
bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
nsRect* aVisibleRect,
nsRect* aDirtyRect,
- bool aSetBase);
+ bool aSetBase,
+ bool* aDirtyRectHasBeenOverriden = nullptr);
void NotifyApproximateFrameVisibilityUpdate(bool aIgnoreDisplayPort);
bool GetDisplayPortAtLastApproximateFrameVisibilityUpdate(nsRect* aDisplayPort);
bool AllowDisplayPortExpiration();
void TriggerDisplayPortExpiration();
void ResetDisplayPortExpiryTimer();
void ScheduleSyntheticMouseMove();
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -622,16 +622,17 @@ public:
, mHasImageRequest(false)
, mHasFirstLetterChild(false)
, mParentIsWrapperAnonBox(false)
, mIsWrapperBoxNeedingRestyle(false)
, mReflowRequestedForCharDataChange(false)
, mForceDescendIntoIfVisible(false)
, mBuiltDisplayList(false)
, mFrameIsModified(false)
+ , mHasOverrideDirtyRegion(false)
, mMayHaveWillChangeBudget(false)
, mIsPrimaryFrame(false)
{
mozilla::PodZero(&mOverflow);
}
nsPresContext* PresContext() const {
return StyleContext()->PresContext();
@@ -4102,16 +4103,19 @@ public:
void SetForceDescendIntoIfVisible(bool aForce) { mForceDescendIntoIfVisible = aForce; }
bool BuiltDisplayList() { return mBuiltDisplayList; }
void SetBuiltDisplayList(bool aBuilt) { mBuiltDisplayList = aBuilt; }
bool IsFrameModified() { return mFrameIsModified; }
void SetFrameIsModified(bool aFrameIsModified) { mFrameIsModified = aFrameIsModified; }
+ bool HasOverrideDirtyRegion() { return mHasOverrideDirtyRegion; }
+ void SetHasOverrideDirtyRegion(bool aHasDirtyRegion) { mHasOverrideDirtyRegion = aHasDirtyRegion; }
+
bool MayHaveWillChangeBudget() { return mMayHaveWillChangeBudget; }
void SetMayHaveWillChangeBudget(bool aHasBudget) { mMayHaveWillChangeBudget = aHasBudget; }
protected:
/**
* Reparent this frame's view if it has one.
*/
@@ -4283,31 +4287,33 @@ protected:
* the last call to CheckAndClearDisplayListState, false
* otherwise. Used for the reftest harness to verify minimal
* display list building.
*/
bool mBuiltDisplayList : 1;
bool mFrameIsModified : 1;
+ bool mHasOverrideDirtyRegion : 1;
+
/**
* True if frame has will-change, and currently has display
* items consuming some of the will-change budget.
*/
bool mMayHaveWillChangeBudget : 1;
private:
/**
* True if this is the primary frame for mContent.
*/
bool mIsPrimaryFrame : 1;
protected:
- // There is a 5-bit gap left here.
+ // There is a 4-bit gap left here.
// Helpers
/**
* Can we stop inside this frame when we're skipping non-rendered whitespace?
* @param aForward [in] Are we moving forward (or backward) in content order.
* @param aOffset [in/out] At what offset into the frame to start looking.
* on output - what offset was reached (whether or not we found a place to stop).
* @return STOP: An appropriate offset was found within this frame,
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -1431,16 +1431,24 @@ public:
const ActiveScrolledRoot* mContainingBlockActiveScrolledRoot;
nsRect mVisibleRect;
nsRect mDirtyRect;
};
NS_DECLARE_FRAME_PROPERTY_DELETABLE(OutOfFlowDisplayDataProperty,
OutOfFlowDisplayData)
+ struct DisplayListBuildingData {
+ RefPtr<AnimatedGeometryRoot> mModifiedAGR = nullptr;
+ nsRect mDirtyRect;
+ };
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(DisplayListBuildingRect, DisplayListBuildingData)
+
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(DisplayListBuildingDisplayPortRect, nsRect)
+
static OutOfFlowDisplayData* GetOutOfFlowData(nsIFrame* aFrame)
{
return aFrame->GetProperty(OutOfFlowDisplayDataProperty());
}
nsPresContext* CurrentPresContext() {
return CurrentPresShellState()->mPresShell->GetPresContext();
}