diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 747ed34bfc3f..9a78659d09bc 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -494,7 +494,7 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame, mFinalTransparentRegion(nullptr), mCurrentFrame(aReferenceFrame), mCurrentReferenceFrame(aReferenceFrame), - mCurrentOffsetToReferenceFrame(0, 0), + mDirtyRect(-1,-1,-1,-1), mGlassDisplayItem(nullptr), mMode(aMode), mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID), @@ -887,11 +887,11 @@ void nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame, const nsRect& aDirtyRect) { PresShellState* state = mPresShellStates.AppendElement(); - if (!state) - return; state->mPresShell = aReferenceFrame->PresContext()->PresShell(); state->mCaretFrame = nullptr; state->mFirstFrameMarkedForDisplay = mFramesMarkedForDisplay.Length(); + state->mPrevDirtyRect = mDirtyRect; + mDirtyRect = aDirtyRect; state->mPresShell->UpdateCanvasBackground(); @@ -935,12 +935,10 @@ nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame, void nsDisplayListBuilder::LeavePresShell(nsIFrame* aReferenceFrame, const nsRect& aDirtyRect) { - if (CurrentPresShellState()->mPresShell != aReferenceFrame->PresContext()->PresShell()) { - // Must have not allocated a state for this presshell, presumably due - // to OOM. - return; - } - + NS_ASSERTION(CurrentPresShellState()->mPresShell == + aReferenceFrame->PresContext()->PresShell(), + "Presshell mismatch"); + mDirtyRect = CurrentPresShellState()->mPrevDirtyRect; ResetMarkedFramesForDisplayList(); mPresShellStates.SetLength(mPresShellStates.Length() - 1); } diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 3b7d453adaed..217356b9fe78 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -313,6 +313,14 @@ public: void SetDescendIntoSubdocuments(bool aDescend) { mDescendIntoSubdocuments = aDescend; } bool GetDescendIntoSubdocuments() { return mDescendIntoSubdocuments; } + /** + * Get dirty rect relative to current frame (the frame that we're calling + * BuildDisplayList on right now). + */ + const nsRect& GetDirtyRect() { return mDirtyRect; } + const nsIFrame* GetCurrentFrame() { return mCurrentFrame; } + const nsIFrame* GetCurrentReferenceFrame() { return mCurrentReferenceFrame; } + /** * Returns true if merging and flattening of display lists should be * performed while computing visibility. @@ -528,20 +536,22 @@ public: /** * A helper class to temporarily set the value of * mIsAtRootOfPseudoStackingContext, and temporarily - * update mCachedOffsetFrame/mCachedOffset from a frame to its child. - * Also saves and restores mClipState. + * set mCurrentFrame and related state. Also temporarily sets mDirtyRect. + * aDirtyRect is relative to aForChild. */ class AutoBuildingDisplayList; friend class AutoBuildingDisplayList; class AutoBuildingDisplayList { public: AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder, - nsIFrame* aForChild, bool aIsRoot) + nsIFrame* aForChild, + const nsRect& aDirtyRect, bool aIsRoot) : mBuilder(aBuilder), mPrevFrame(aBuilder->mCurrentFrame), mPrevReferenceFrame(aBuilder->mCurrentReferenceFrame), mPrevLayerEventRegions(aBuilder->mLayerEventRegions), mPrevOffset(aBuilder->mCurrentOffsetToReferenceFrame), + mPrevDirtyRect(aBuilder->mDirtyRect), mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext), mPrevAncestorHasTouchEventHandler(aBuilder->mAncestorHasTouchEventHandler) { @@ -556,13 +566,18 @@ public: &aBuilder->mCurrentOffsetToReferenceFrame); } aBuilder->mCurrentFrame = aForChild; + aBuilder->mDirtyRect = aDirtyRect; aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot; } + void SetDirtyRect(const nsRect& aRect) { + mBuilder->mDirtyRect = aRect; + } ~AutoBuildingDisplayList() { mBuilder->mCurrentFrame = mPrevFrame; mBuilder->mCurrentReferenceFrame = mPrevReferenceFrame; mBuilder->mLayerEventRegions = mPrevLayerEventRegions; mBuilder->mCurrentOffsetToReferenceFrame = mPrevOffset; + mBuilder->mDirtyRect = mPrevDirtyRect; mBuilder->mIsAtRootOfPseudoStackingContext = mPrevIsAtRootOfPseudoStackingContext; mBuilder->mAncestorHasTouchEventHandler = mPrevAncestorHasTouchEventHandler; } @@ -572,6 +587,7 @@ public: const nsIFrame* mPrevReferenceFrame; nsDisplayLayerEventRegions* mPrevLayerEventRegions; nsPoint mPrevOffset; + nsRect mPrevDirtyRect; bool mPrevIsAtRootOfPseudoStackingContext; bool mPrevAncestorHasTouchEventHandler; }; @@ -736,6 +752,7 @@ private: struct PresShellState { nsIPresShell* mPresShell; nsIFrame* mCaretFrame; + nsRect mPrevDirtyRect; uint32_t mFirstFrameMarkedForDisplay; bool mIsBackgroundOnly; }; @@ -763,6 +780,8 @@ private: const nsIFrame* mCurrentReferenceFrame; // The offset from mCurrentFrame to mCurrentReferenceFrame. nsPoint mCurrentOffsetToReferenceFrame; + // Relative to mCurrentFrame. + nsRect mDirtyRect; nsRegion mExcludedGlassRegion; // The display item for the Windows window glass background, if any nsDisplayItem* mGlassDisplayItem; diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index aa230b87534f..37bc7a05f5b1 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -1907,6 +1907,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, AutoSaveRestoreBlendMode autoRestoreBlendMode(*aBuilder); aBuilder->SetContainsBlendModes(BlendModeSet()); + nsPoint offsetToReferenceFrame = aBuilder->ToReferenceFrame(this); + if (isTransformed) { const nsRect overflow = GetVisualOverflowRectRelativeToSelf(); if (aBuilder->IsForPainting() && @@ -1917,11 +1919,10 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, return; } - nsPoint offset = aBuilder->ToReferenceFrame(this); - dirtyRect += offset; - + dirtyRect += offsetToReferenceFrame; nsRect untransformedDirtyRect; - if (nsDisplayTransform::UntransformRect(dirtyRect, overflow, this, offset, &untransformedDirtyRect)) { + if (nsDisplayTransform::UntransformRect(dirtyRect, overflow, this, + offsetToReferenceFrame, &untransformedDirtyRect)) { dirtyRect = untransformedDirtyRect; } else { NS_WARNING("Unable to untransform dirty rect!"); @@ -1940,6 +1941,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, nsLayoutUtils::SCROLLABLE_SAME_DOC | nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN)); + nsDisplayListBuilder::AutoBuildingDisplayList + buildingDisplayList(aBuilder, this, dirtyRect, true); DisplayListClipState::AutoSaveRestore clipState(aBuilder); if (isTransformed || useOpacity || useBlendMode || usingSVGEffects || useStickyPosition) { @@ -1952,8 +1955,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, } nsDisplayListCollection set; - { - nsDisplayListBuilder::AutoBuildingDisplayList rootSetter(aBuilder, this, true); + { DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder); nsDisplayListBuilder::AutoInTransformSetter inTransformSetter(aBuilder, inTransform); @@ -1994,7 +1996,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, set.PositionedDescendants()->DeleteAll(); set.Outlines()->DeleteAll(); } - + // This z-order sort also sorts secondarily by content order. We need to do // this so that boxes produced by the same element are placed together // in the sort. Consider a position:relative inline element that breaks @@ -2002,7 +2004,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, // children should be z-ordered after all the boxes for the position:relative // element itself. set.PositionedDescendants()->SortByZOrder(aBuilder, GetContent()); - + nsDisplayList resultList; // Now follow the rules of http://www.w3.org/TR/CSS21/zindex.html // 1,2: backgrounds and borders @@ -2072,8 +2074,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, new (aBuilder) nsDisplayStickyPosition(aBuilder, this, &resultList)); } - /* If we're going to apply a transformation and don't have preserve-3d set, wrap - * everything in an nsDisplayTransform. If there's nothing in the list, don't add + /* If we're going to apply a transformation and don't have preserve-3d set, wrap + * everything in an nsDisplayTransform. If there's nothing in the list, don't add * anything. * * For the preserve-3d case we want to individually wrap every child in the list with @@ -2086,6 +2088,9 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, if (isTransformed && !resultList.IsEmpty()) { // Restore clip state now so nsDisplayTransform is clipped properly. clipState.Restore(); + // Revert to the dirtyrect coming in from the parent, without our transform + // taken into account. + buildingDisplayList.SetDirtyRect(aDirtyRect + offsetToReferenceFrame); if (Preserves3DChildren()) { WrapPreserve3DList(this, aBuilder, &resultList); @@ -2293,7 +2298,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, buildingInFixedPos(aBuilder, isInFixedPos); nsDisplayListBuilder::AutoBuildingDisplayList - buildingForChild(aBuilder, child, pseudoStackingContext); + buildingForChild(aBuilder, child, dirty, pseudoStackingContext); DisplayListClipState::AutoClipMultiple clipState(aBuilder); CheckForTouchEventHandler(aBuilder, child);