Bug 1404181 - Part 15: Add the notion of 'modified' frames, that need new display items built for them (and all their descendants). r?mstange
MozReview-Commit-ID: 66vbfSDeOpK
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -958,16 +958,65 @@ nsIFrame::RemoveDisplayItemDataForDeleti
if (items) {
for (nsDisplayItem* item : *items) {
item->RemoveFrame(this);
}
delete items;
}
}
+void
+nsIFrame::MarkNeedsDisplayItemRebuild()
+{
+ if (!gfxPrefs::LayoutRetainDisplayList() || !XRE_IsContentProcess() ||
+ IsFrameModified()) {
+ // Skip non-content processes and frames that are already marked modified.
+ return;
+ }
+
+ nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(this);
+ MOZ_ASSERT(displayRoot);
+
+ nsIFrame* viewport = nsLayoutUtils::GetViewportFrame(this);
+ MOZ_ASSERT(viewport);
+
+ std::vector<WeakFrame>* modifiedFrames =
+ viewport->GetProperty(nsIFrame::ModifiedFrameList());
+
+ if (!modifiedFrames) {
+ modifiedFrames = new std::vector<WeakFrame>();
+ viewport->SetProperty(nsIFrame::ModifiedFrameList(), modifiedFrames);
+ }
+
+ modifiedFrames->emplace_back(this);
+
+ // TODO: this is a bit of a hack. We are using ModifiedFrameList property to
+ // decide whether we are trying to reuse the display list.
+ if (displayRoot != viewport &&
+ !displayRoot->HasProperty(nsIFrame::ModifiedFrameList())) {
+ displayRoot->SetProperty(nsIFrame::ModifiedFrameList(),
+ new std::vector<WeakFrame>());
+ }
+
+ MOZ_ASSERT(PresContext()->LayoutPhaseCount(eLayoutPhase_DisplayListBuilding) == 0);
+ SetFrameIsModified(true);
+
+ // Hopefully this is cheap, but we could use a frame state bit to note
+ // the presence of dependencies to speed it up.
+ DisplayItemArray* items = GetProperty(DisplayItems());
+ if (items) {
+ for (nsDisplayItem* i : *items) {
+ if (i->GetDependentFrame() == this &&
+ !i->HasDeletedFrame()) {
+ i->Frame()->MarkNeedsDisplayItemRebuild();
+ }
+ }
+ }
+}
+
// Subclass hook for style post processing
/* virtual */ void
nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
{
if (nsSVGUtils::IsInSVGTextSubtree(this)) {
SVGTextFrame* svgTextFrame = static_cast<SVGTextFrame*>(
nsLayoutUtils::GetClosestFrameOfType(this, LayoutFrameType::SVGText));
nsIFrame* anonBlock = svgTextFrame->PrincipalChildList().FirstChild();
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -621,16 +621,17 @@ public:
, mMayHaveRoundedCorners(false)
, mHasImageRequest(false)
, mHasFirstLetterChild(false)
, mParentIsWrapperAnonBox(false)
, mIsWrapperBoxNeedingRestyle(false)
, mReflowRequestedForCharDataChange(false)
, mForceDescendIntoIfVisible(false)
, mBuiltDisplayList(false)
+ , mFrameIsModified(false)
, mIsPrimaryFrame(false)
{
mozilla::PodZero(&mOverflow);
}
nsPresContext* PresContext() const {
return StyleContext()->PresContext();
}
@@ -1230,16 +1231,17 @@ public:
NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BClampMarginBoxMinSizeProperty, nscoord)
NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(IBaselinePadProperty, nscoord)
NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BBaselinePadProperty, nscoord)
NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(GenConProperty, ContentArray,
DestroyContentArray)
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(ModifiedFrameList, std::vector<WeakFrame>)
NS_DECLARE_FRAME_PROPERTY_DELETABLE(DisplayItems, DisplayItemArray)
NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BidiDataProperty, mozilla::FrameBidiData)
NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(PlaceholderFrameProperty, nsPlaceholderFrame)
NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(WebRenderUserDataProperty, WebRenderUserDataTable, DestroyWebRenderUserDataTable)
static void DestroyWebRenderUserDataTable(WebRenderUserDataTable* aTable);
@@ -3064,16 +3066,18 @@ public:
enum {
UPDATE_IS_ASYNC = 1 << 0
};
Layer* InvalidateLayer(DisplayItemType aDisplayItemKey,
const nsIntRect* aDamageRect = nullptr,
const nsRect* aFrameDamageRect = nullptr,
uint32_t aFlags = 0);
+ void MarkNeedsDisplayItemRebuild();
+
/**
* Returns a rect that encompasses everything that might be painted by
* this frame. This includes this frame, all its descendant frames, this
* frame's outline, and descendant frames' outline, but does not include
* areas clipped out by the CSS "overflow" and "clip" properties.
*
* HasOverflowRects() (below) will return true when this overflow
* rect has been explicitly set, even if it matches mRect.
@@ -4094,16 +4098,19 @@ public:
void DestroyAnonymousContent(already_AddRefed<nsIContent> aContent);
bool ForceDescendIntoIfVisible() { return mForceDescendIntoIfVisible; }
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; }
+
protected:
/**
* Reparent this frame's view if it has one.
*/
void ReparentFrameViewTo(nsViewManager* aViewManager,
nsView* aNewParentView,
nsView* aOldParentView);
@@ -4270,16 +4277,18 @@ protected:
/**
* True if we have built display items for this frame since
* the last call to CheckAndClearDisplayListState, false
* otherwise. Used for the reftest harness to verify minimal
* display list building.
*/
bool mBuiltDisplayList : 1;
+ bool mFrameIsModified : 1;
+
private:
/**
* True if this is the primary frame for mContent.
*/
bool mIsPrimaryFrame : 1;
protected:
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -953,17 +953,18 @@ nsDisplayListBuilder::nsDisplayListBuild
mAncestorHasApzAwareEventHandler(false),
mHaveScrollableDisplayPort(false),
mWindowDraggingAllowed(false),
mIsBuildingForPopup(nsLayoutUtils::IsPopup(aReferenceFrame)),
mForceLayerForScrollParent(false),
mAsyncPanZoomEnabled(nsLayoutUtils::AsyncPanZoomEnabled(aReferenceFrame)),
mBuildingInvisibleItems(false),
mHitTestShouldStopAtFirstOpaque(false),
- mIsBuilding(false)
+ mIsBuilding(false),
+ mInInvalidSubtree(false)
{
MOZ_COUNT_CTOR(nsDisplayListBuilder);
nsPresContext* pc = aReferenceFrame->PresContext();
nsIPresShell *shell = pc->PresShell();
if (pc->IsRenderingOnlySelection()) {
nsCOMPtr<nsISelectionController> selcon(do_QueryInterface(shell));
if (selcon) {
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -49,16 +49,17 @@
#include <algorithm>
class gfxContext;
class nsIContent;
class nsDisplayList;
class nsDisplayTableItem;
class nsISelection;
class nsIScrollableFrame;
+class nsSubDocumentFrame;
class nsDisplayLayerEventRegions;
class nsDisplayScrollInfoLayer;
class nsCaret;
namespace mozilla {
class FrameLayerBuilder;
namespace layers {
class Layer;
@@ -613,17 +614,23 @@ public:
bool IsPartialUpdate() const { return mPartialUpdate; }
void SetPartialUpdate(bool aPartial) { mPartialUpdate = aPartial; }
bool IsBuilding() const { return mIsBuilding; }
void SetIsBuilding(bool aIsBuilding)
{
mIsBuilding = aIsBuilding;
- }
+ for (nsIFrame* f : mModifiedFramesDuringBuilding) {
+ f->SetFrameIsModified(false);
+ }
+ mModifiedFramesDuringBuilding.Clear();
+ }
+
+ bool InInvalidSubtree() const { return mInInvalidSubtree; }
/**
* Allows callers to selectively override the regular paint suppression checks,
* so that methods like GetFrameForPoint work when painting is suppressed.
*/
void IgnorePaintSuppression() { mIgnoreSuppression = true; }
/**
* @return Returns if this builder will ignore paint suppression.
@@ -987,17 +994,18 @@ public:
mPrevReferenceFrame(aBuilder->mCurrentReferenceFrame),
mPrevLayerEventRegions(aBuilder->mLayerEventRegions),
mPrevOffset(aBuilder->mCurrentOffsetToReferenceFrame),
mPrevVisibleRect(aBuilder->mVisibleRect),
mPrevDirtyRect(aBuilder->mDirtyRect),
mPrevAGR(aBuilder->mCurrentAGR),
mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext),
mPrevAncestorHasApzAwareEventHandler(aBuilder->mAncestorHasApzAwareEventHandler),
- mPrevBuildingInvisibleItems(aBuilder->mBuildingInvisibleItems)
+ mPrevBuildingInvisibleItems(aBuilder->mBuildingInvisibleItems),
+ mPrevInInvalidSubtree(aBuilder->mInInvalidSubtree)
{
if (aForChild->IsTransformed()) {
aBuilder->mCurrentOffsetToReferenceFrame = nsPoint();
aBuilder->mCurrentReferenceFrame = aForChild;
} else if (aBuilder->mCurrentFrame == aForChild->GetParent()) {
aBuilder->mCurrentOffsetToReferenceFrame += aForChild->GetPosition();
} else {
aBuilder->mCurrentReferenceFrame =
@@ -1013,16 +1021,17 @@ public:
} else if (aForChild != aBuilder->mCurrentFrame) {
aBuilder->mCurrentAGR = aBuilder->FindAnimatedGeometryRootFor(aForChild);
}
MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(aBuilder->RootReferenceFrame(), *aBuilder->mCurrentAGR));
aBuilder->mCurrentFrame = aForChild;
aBuilder->mVisibleRect = aVisibleRect;
aBuilder->mDirtyRect = aDirtyRect;
aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot;
+ aBuilder->mInInvalidSubtree = aBuilder->mInInvalidSubtree || aForChild->IsFrameModified();
}
void SetReferenceFrameAndCurrentOffset(const nsIFrame* aFrame, const nsPoint& aOffset) {
mBuilder->mCurrentReferenceFrame = aFrame;
mBuilder->mCurrentOffsetToReferenceFrame = aOffset;
}
bool IsAnimatedGeometryRoot() const {
return mCurrentAGRState == AGR_YES;
}
@@ -1038,30 +1047,32 @@ public:
mBuilder->mLayerEventRegions = mPrevLayerEventRegions;
mBuilder->mCurrentOffsetToReferenceFrame = mPrevOffset;
mBuilder->mVisibleRect = mPrevVisibleRect;
mBuilder->mDirtyRect = mPrevDirtyRect;
mBuilder->mCurrentAGR = mPrevAGR;
mBuilder->mIsAtRootOfPseudoStackingContext = mPrevIsAtRootOfPseudoStackingContext;
mBuilder->mAncestorHasApzAwareEventHandler = mPrevAncestorHasApzAwareEventHandler;
mBuilder->mBuildingInvisibleItems = mPrevBuildingInvisibleItems;
+ mBuilder->mInInvalidSubtree = mPrevInInvalidSubtree;
}
private:
nsDisplayListBuilder* mBuilder;
AGRState mCurrentAGRState;
const nsIFrame* mPrevFrame;
const nsIFrame* mPrevReferenceFrame;
nsDisplayLayerEventRegions* mPrevLayerEventRegions;
nsPoint mPrevOffset;
nsRect mPrevVisibleRect;
nsRect mPrevDirtyRect;
RefPtr<AnimatedGeometryRoot> mPrevAGR;
bool mPrevIsAtRootOfPseudoStackingContext;
bool mPrevAncestorHasApzAwareEventHandler;
bool mPrevBuildingInvisibleItems;
+ bool mPrevInInvalidSubtree;
};
/**
* A helper class to temporarily set the value of mInTransform.
*/
class AutoInTransformSetter;
friend class AutoInTransformSetter;
class AutoInTransformSetter {
@@ -1562,16 +1573,24 @@ public:
mPreserves3DCtx.mDirtyRect = mDirtyRect;
}
bool IsBuildingInvisibleItems() const { return mBuildingInvisibleItems; }
void SetBuildingInvisibleItems(bool aBuildingInvisibleItems) {
mBuildingInvisibleItems = aBuildingInvisibleItems;
}
+ void MarkFrameModifiedDuringBuilding(nsIFrame* aFrame)
+ {
+ if (!aFrame->IsFrameModified()) {
+ mModifiedFramesDuringBuilding.AppendElement(aFrame);
+ aFrame->SetFrameIsModified(true);
+ }
+ }
+
/**
* This is a convenience function to ease the transition until AGRs and ASRs
* are unified.
*/
AnimatedGeometryRoot* AnimatedGeometryRootForASR(const ActiveScrolledRoot* aASR);
bool HitTestShouldStopAtFirstOpaque() const {
return mHitTestShouldStopAtFirstOpaque;
@@ -1684,16 +1703,18 @@ private:
// and thus is in-budget.
nsTHashtable<nsPtrHashKey<nsIFrame> > mWillChangeBudgetSet;
// Area of animated geometry root budget already allocated
uint32_t mUsedAGRBudget;
// Set of frames already counted in budget
nsTHashtable<nsPtrHashKey<nsIFrame> > mAGRBudgetSet;
+ nsTArray<nsIFrame*> mModifiedFramesDuringBuilding;
+
// Relative to mCurrentFrame.
nsRect mVisibleRect;
nsRect mDirtyRect;
nsRegion mWindowExcludeGlassRegion;
nsRegion mWindowOpaqueRegion;
LayoutDeviceIntRegion mWindowDraggingRegion;
LayoutDeviceIntRegion mWindowNoDraggingRegion;
// The display item for the Windows window glass background, if any
@@ -1743,16 +1764,17 @@ private:
bool mHaveScrollableDisplayPort;
bool mWindowDraggingAllowed;
bool mIsBuildingForPopup;
bool mForceLayerForScrollParent;
bool mAsyncPanZoomEnabled;
bool mBuildingInvisibleItems;
bool mHitTestShouldStopAtFirstOpaque;
bool mIsBuilding;
+ bool mInInvalidSubtree;
};
class nsDisplayItem;
class nsDisplayList;
/**
* nsDisplayItems are put in singly-linked lists rooted in an nsDisplayList.
* nsDisplayItemLink holds the link. The lists are linked from lowest to
* highest in z-order.