Bug 1344971 - Part 1: Create OutOfFlowDisplayData for the parent of the OOF frame so they can be shared. r?mstange
MozReview-Commit-ID: 8MH4JAyLU8w
--- a/layout/generic/ViewportFrame.cpp
+++ b/layout/generic/ViewportFrame.cpp
@@ -101,17 +101,17 @@ BuildDisplayListForTopLayerFrame(nsDispl
nsDisplayList* aList)
{
nsRect dirty;
DisplayListClipState::AutoClipMultiple clipState(aBuilder);
nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
nsDisplayListBuilder::OutOfFlowDisplayData*
savedOutOfFlowData = nsDisplayListBuilder::GetOutOfFlowData(aFrame);
if (savedOutOfFlowData) {
- dirty = savedOutOfFlowData->mDirtyRect;
+ dirty = savedOutOfFlowData->GetDirtyRectForFrame(aBuilder, aFrame);
// This function is called after we've finished building display items for
// the root scroll frame. That means that the content clip from the root
// scroll frame is no longer on aBuilder. However, we need to make sure
// that the display items we build in this function have finite clipped
// bounds with respect to the root ASR, so we restore the *combined clip*
// that we saved earlier. The combined clip will include the clip from the
// root scroll frame.
clipState.SetClipChainForContainingBlockDescendants(
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -2817,17 +2817,17 @@ nsIFrame::BuildDisplayListForChild(nsDis
// could call GetType again but since we don't currently need it, let's
// avoid the virtual call.
childType = nullptr;
// Recheck NS_FRAME_TOO_DEEP_IN_FRAME_TREE
if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
return;
savedOutOfFlowData = nsDisplayListBuilder::GetOutOfFlowData(child);
if (savedOutOfFlowData) {
- dirty = savedOutOfFlowData->mDirtyRect;
+ dirty = savedOutOfFlowData->GetDirtyRectForFrame(aBuilder, child);
} else {
// The out-of-flow frame did not intersect the dirty area. We may still
// need to traverse into it, since it may contain placeholders we need
// to enter to reach other out-of-flow frames that are visible.
dirty.SetEmpty();
}
pseudoStackingContext = true;
}
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -1022,82 +1022,58 @@ nsDisplayListBuilder::FindAnimatedGeomet
if (viewportFrame) {
return FindAnimatedGeometryRootFor(viewportFrame);
}
}
return FindAnimatedGeometryRootFor(aItem->Frame());
}
-void nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame,
+bool nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame,
nsIFrame* aFrame,
const nsRect& aDirtyRect)
{
- nsRect dirtyRectRelativeToDirtyFrame = aDirtyRect;
- if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame) &&
- IsPaintingToWindow()) {
- NS_ASSERTION(aDirtyFrame == aFrame->GetParent(), "Dirty frame should be viewport frame");
- // position: fixed items are reflowed into and only drawn inside the
- // viewport, or the scroll position clamping scrollport size, if one is
- // set.
- nsIPresShell* ps = aFrame->PresContext()->PresShell();
- dirtyRectRelativeToDirtyFrame.MoveTo(0, 0);
- if (ps->IsScrollPositionClampingScrollPortSizeSet()) {
- dirtyRectRelativeToDirtyFrame.SizeTo(ps->GetScrollPositionClampingScrollPortSize());
- } else {
- dirtyRectRelativeToDirtyFrame.SizeTo(aDirtyFrame->GetSize());
- }
- }
- nsRect dirty = dirtyRectRelativeToDirtyFrame - aFrame->GetOffsetTo(aDirtyFrame);
+ MOZ_ASSERT(aFrame->GetParent() == aDirtyFrame);
+ nsRect dirty = OutOfFlowDisplayData::ComputeDirtyRectForFrame(this, aFrame, aDirtyRect);
nsRect overflowRect = aFrame->GetVisualOverflowRect();
if (aFrame->IsTransformed() &&
EffectCompositor::HasAnimationsForCompositor(aFrame,
eCSSProperty_transform)) {
/**
* Add a fuzz factor to the overflow rectangle so that elements only just
* out of view are pulled into the display list, so they can be
* prerendered if necessary.
*/
overflowRect.Inflate(nsPresContext::CSSPixelsToAppUnits(32));
}
if (!dirty.IntersectRect(dirty, overflowRect) &&
!(aFrame->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
- return;
- }
-
- // mClipState.GetClipChainForContainingBlockDescendants can return pointers
- // to objects on the stack, so we need to clone the chain.
- const DisplayItemClipChain* clipChain =
- CopyWholeChain(mClipState.GetClipChainForContainingBlockDescendants());
- const DisplayItemClipChain* combinedClipChain = mClipState.GetCurrentCombinedClipChain(this);
- const ActiveScrolledRoot* asr = mCurrentActiveScrolledRoot;
- OutOfFlowDisplayData* data = new OutOfFlowDisplayData(clipChain, combinedClipChain, asr, dirty);
- aFrame->Properties().Set(nsDisplayListBuilder::OutOfFlowDisplayDataProperty(), data);
+ return false;
+ }
MarkFrameForDisplay(aFrame, aDirtyFrame);
+ return true;
}
static void UnmarkFrameForDisplay(nsIFrame* aFrame) {
- nsPresContext* presContext = aFrame->PresContext();
- presContext->PropertyTable()->
- Delete(aFrame, nsDisplayListBuilder::OutOfFlowDisplayDataProperty());
-
for (nsIFrame* f = aFrame; f;
f = nsLayoutUtils::GetParentOrPlaceholderFor(f)) {
if (!(f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO))
return;
f->RemoveStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
}
}
nsDisplayListBuilder::~nsDisplayListBuilder() {
NS_ASSERTION(mFramesMarkedForDisplay.Length() == 0,
"All frames should have been unmarked");
+ NS_ASSERTION(mFramesWithOOFData.Length() == 0,
+ "All OOF data should have been removed");
NS_ASSERTION(mPresShellStates.Length() == 0,
"All presshells should have been exited");
NS_ASSERTION(!mCurrentTableItem, "No table item should be active");
nsCSSRendering::EndFrameTreesLocked();
for (ActiveScrolledRoot* asr : mActiveScrolledRoots) {
asr->ActiveScrolledRoot::~ActiveScrolledRoot();
@@ -1150,16 +1126,17 @@ nsDisplayListBuilder::GetCaret() {
void
nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame,
bool aPointerEventsNoneDoc)
{
PresShellState* state = mPresShellStates.AppendElement();
state->mPresShell = aReferenceFrame->PresContext()->PresShell();
state->mCaretFrame = nullptr;
state->mFirstFrameMarkedForDisplay = mFramesMarkedForDisplay.Length();
+ state->mFirstFrameWithOOFData = mFramesWithOOFData.Length();
state->mPresShell->UpdateCanvasBackground();
if (mIsPaintingToWindow) {
mReferenceFrame->AddPaintedPresShell(state->mPresShell);
state->mPresShell->IncrementPaintCount();
}
@@ -1255,36 +1232,62 @@ nsDisplayListBuilder::ResetMarkedFramesF
{
// Unmark and pop off the frames marked for display in this pres shell.
uint32_t firstFrameForShell = CurrentPresShellState()->mFirstFrameMarkedForDisplay;
for (uint32_t i = firstFrameForShell;
i < mFramesMarkedForDisplay.Length(); ++i) {
UnmarkFrameForDisplay(mFramesMarkedForDisplay[i]);
}
mFramesMarkedForDisplay.SetLength(firstFrameForShell);
+
+ firstFrameForShell = CurrentPresShellState()->mFirstFrameWithOOFData;
+ for (uint32_t i = firstFrameForShell;
+ i < mFramesWithOOFData.Length(); ++i) {
+ nsPresContext* presContext = mFramesWithOOFData[i]->PresContext();
+ presContext->PropertyTable()->
+ Delete(mFramesWithOOFData[i], nsDisplayListBuilder::OutOfFlowDisplayDataProperty());
+
+ }
+ mFramesWithOOFData.SetLength(firstFrameForShell);
}
void
nsDisplayListBuilder::MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
const nsFrameList& aFrames,
- const nsRect& aDirtyRect) {
+ const nsRect& aDirtyRect)
+{
mFramesMarkedForDisplay.SetCapacity(mFramesMarkedForDisplay.Length() + aFrames.GetLength());
+ bool markedFrames = false;
for (nsIFrame* e : aFrames) {
// Skip the AccessibleCaret frame when building no caret.
if (!IsBuildingCaret()) {
nsIContent* content = e->GetContent();
if (content && content->IsInNativeAnonymousSubtree() && content->IsElement()) {
auto classList = content->AsElement()->ClassList();
if (classList->Contains(NS_LITERAL_STRING("moz-accessiblecaret"))) {
continue;
}
}
}
- mFramesMarkedForDisplay.AppendElement(e);
- MarkOutOfFlowFrameForDisplay(aDirtyFrame, e, aDirtyRect);
+ if (MarkOutOfFlowFrameForDisplay(aDirtyFrame, e, aDirtyRect)) {
+ mFramesMarkedForDisplay.AppendElement(e);
+ markedFrames = true;
+ }
+ }
+
+ if (markedFrames) {
+ // mClipState.GetClipChainForContainingBlockDescendants can return pointers
+ // to objects on the stack, so we need to clone the chain.
+ const DisplayItemClipChain* clipChain =
+ CopyWholeChain(mClipState.GetClipChainForContainingBlockDescendants());
+ const DisplayItemClipChain* combinedClipChain = mClipState.GetCurrentCombinedClipChain(this);
+ const ActiveScrolledRoot* asr = mCurrentActiveScrolledRoot;
+ OutOfFlowDisplayData* data = new OutOfFlowDisplayData(clipChain, combinedClipChain, asr, aDirtyRect);
+ aDirtyFrame->Properties().Set(nsDisplayListBuilder::OutOfFlowDisplayDataProperty(), data);
+ mFramesWithOOFData.AppendElement(aDirtyFrame);
}
if (!aDirtyFrame->GetParent()) {
// This is the viewport frame of aDirtyFrame's presshell.
// Store the current display data so that it can be used for fixed
// background images.
NS_ASSERTION(CurrentPresShellState()->mPresShell ==
aDirtyFrame->PresContext()->PresShell(),
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -1219,24 +1219,53 @@ public:
, mCombinedClipChain(aCombinedClipChain)
, mContainingBlockActiveScrolledRoot(aContainingBlockActiveScrolledRoot)
, mDirtyRect(aDirtyRect)
{}
const DisplayItemClipChain* mContainingBlockClipChain;
const DisplayItemClipChain* mCombinedClipChain; // only necessary for the special case of top layer
const ActiveScrolledRoot* mContainingBlockActiveScrolledRoot;
nsRect mDirtyRect;
+
+
+ static nsRect ComputeDirtyRectForFrame(nsDisplayListBuilder* aBuilder,
+ nsIFrame* aFrame,
+ const nsRect& aDirtyRect) {
+ nsRect dirtyRectRelativeToDirtyFrame = aDirtyRect;
+ if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame) &&
+ aBuilder->IsPaintingToWindow()) {
+ // position: fixed items are reflowed into and only drawn inside the
+ // viewport, or the scroll position clamping scrollport size, if one is
+ // set.
+ nsIPresShell* ps = aFrame->PresContext()->PresShell();
+ dirtyRectRelativeToDirtyFrame.MoveTo(0, 0);
+ if (ps->IsScrollPositionClampingScrollPortSizeSet()) {
+ dirtyRectRelativeToDirtyFrame.SizeTo(ps->GetScrollPositionClampingScrollPortSize());
+ } else {
+ dirtyRectRelativeToDirtyFrame.SizeTo(aFrame->GetParent()->GetSize());
+ }
+ }
+ return dirtyRectRelativeToDirtyFrame - aFrame->GetPosition();
+ }
+
+ nsRect GetDirtyRectForFrame(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) {
+ return ComputeDirtyRectForFrame(aBuilder, aFrame, mDirtyRect);
+ }
};
NS_DECLARE_FRAME_PROPERTY_DELETABLE(OutOfFlowDisplayDataProperty,
OutOfFlowDisplayData)
static OutOfFlowDisplayData* GetOutOfFlowData(nsIFrame* aFrame)
{
- return aFrame->Properties().Get(OutOfFlowDisplayDataProperty());
+ if (!(aFrame->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO) ||
+ !aFrame->GetParent()) {
+ return nullptr;
+ }
+ return aFrame->GetParent()->Properties().Get(OutOfFlowDisplayDataProperty());
}
nsPresContext* CurrentPresContext() {
return CurrentPresShellState()->mPresShell->GetPresContext();
}
OutOfFlowDisplayData* GetCurrentFixedBackgroundDisplayData()
{
@@ -1382,17 +1411,17 @@ public:
bool HitTestShouldStopAtFirstOpaque() const {
return mHitTestShouldStopAtFirstOpaque;
}
void SetHitTestShouldStopAtFirstOpaque(bool aHitTestShouldStopAtFirstOpaque) {
mHitTestShouldStopAtFirstOpaque = aHitTestShouldStopAtFirstOpaque;
}
private:
- void MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame,
+ bool MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame,
const nsRect& aDirtyRect);
/**
* Returns whether a frame acts as an animated geometry root, optionally
* returning the next ancestor to check.
*/
bool IsAnimatedGeometryRoot(nsIFrame* aFrame, nsIFrame** aParent = nullptr);
@@ -1423,16 +1452,17 @@ private:
bool AddToAGRBudget(nsIFrame* aFrame);
struct PresShellState {
nsIPresShell* mPresShell;
nsIFrame* mCaretFrame;
nsRect mCaretRect;
mozilla::Maybe<OutOfFlowDisplayData> mFixedBackgroundDisplayData;
uint32_t mFirstFrameMarkedForDisplay;
+ uint32_t mFirstFrameWithOOFData;
bool mIsBackgroundOnly;
// This is a per-document flag turning off event handling for all content
// in the document, and is set when we enter a subdocument for a pointer-
// events:none frame.
bool mInsidePointerEventsNoneDoc;
};
PresShellState* CurrentPresShellState() {
@@ -1451,16 +1481,17 @@ private:
nsIFrame* const mReferenceFrame;
nsIFrame* mIgnoreScrollFrame;
nsDisplayLayerEventRegions* mLayerEventRegions;
PLArenaPool mPool;
nsCOMPtr<nsISelection> mBoundingSelection;
AutoTArray<PresShellState,8> mPresShellStates;
AutoTArray<nsIFrame*,100> mFramesMarkedForDisplay;
+ AutoTArray<nsIFrame*,20> mFramesWithOOFData;
AutoTArray<ThemeGeometry,2> mThemeGeometries;
nsDisplayTableItem* mCurrentTableItem;
DisplayListClipState mClipState;
const ActiveScrolledRoot* mCurrentActiveScrolledRoot;
const ActiveScrolledRoot* mCurrentContainerASR;
// mCurrentFrame is the frame that we're currently calling (or about to call)
// BuildDisplayList on.
const nsIFrame* mCurrentFrame;