mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 424915. Improve display list analysis so that sites with content covered by the scrolling element, such as GMail, can use bitblit scrolling. r+sr=dbaron,a=beltzner
This commit is contained in:
parent
ef3215ce8e
commit
1dead6507c
@ -52,9 +52,9 @@
|
||||
#include "gfxContext.h"
|
||||
|
||||
nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||
PRBool aIsForEvents, PRBool aBuildCaret, nsIFrame* aMovingFrame)
|
||||
PRBool aIsForEvents, PRBool aBuildCaret)
|
||||
: mReferenceFrame(aReferenceFrame),
|
||||
mMovingFrame(aMovingFrame),
|
||||
mMovingFrame(nsnull),
|
||||
mIgnoreScrollFrame(nsnull),
|
||||
mCurrentTableItem(nsnull),
|
||||
mBuildCaret(aBuildCaret),
|
||||
@ -233,23 +233,23 @@ nsDisplayItem::OptimizeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRect bounds = GetBounds(aBuilder);
|
||||
if (!aVisibleRegion->Intersects(bounds))
|
||||
return PR_FALSE;
|
||||
|
||||
|
||||
nsIFrame* f = GetUnderlyingFrame();
|
||||
NS_ASSERTION(f, "GetUnderlyingFrame() must return non-null for leaf items");
|
||||
if (aBuilder->HasMovingFrames() && aBuilder->IsMovingFrame(f)) {
|
||||
// If this frame is in the moving subtree, and it doesn't
|
||||
// require repainting just because it's moved, then just remove it now
|
||||
// because it's not relevant.
|
||||
if (!IsVaryingRelativeToFrame(aBuilder, aBuilder->GetRootMovingFrame()))
|
||||
return PR_FALSE;
|
||||
// keep it, but don't let it cover other display items (see nsLayoutUtils::
|
||||
// ComputeRepaintRegionForCopy)
|
||||
return PR_TRUE;
|
||||
}
|
||||
PRBool isMoving = aBuilder->IsMovingFrame(f);
|
||||
|
||||
if (IsOpaque(aBuilder)) {
|
||||
aVisibleRegion->SimpleSubtract(bounds);
|
||||
nsRect opaqueArea = bounds;
|
||||
if (isMoving) {
|
||||
// The display list should include items for both the before and after
|
||||
// states (see nsLayoutUtils::ComputeRepaintRegionForCopy. So the
|
||||
// only area we want to cover is the the area that was opaque in the
|
||||
// before state and in the after state.
|
||||
opaqueArea.IntersectRect(bounds - aBuilder->GetMoveDelta(), bounds);
|
||||
}
|
||||
aVisibleRegion->SimpleSubtract(opaqueArea);
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
@ -509,26 +509,29 @@ nsDisplayBackground::IsUniform(nsDisplayListBuilder* aBuilder) {
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsDisplayBackground::IsVaryingRelativeToFrame(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aAncestorFrame)
|
||||
nsDisplayBackground::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder)
|
||||
{
|
||||
NS_ASSERTION(aBuilder->IsMovingFrame(mFrame),
|
||||
"IsVaryingRelativeToMovingFrame called on non-moving frame!");
|
||||
|
||||
nsPresContext* presContext = mFrame->PresContext();
|
||||
PRBool isCanvas;
|
||||
const nsStyleBackground* bg;
|
||||
PRBool hasBG =
|
||||
nsCSSRendering::FindBackground(mFrame->PresContext(), mFrame, &bg, &isCanvas);
|
||||
nsCSSRendering::FindBackground(presContext, mFrame, &bg, &isCanvas);
|
||||
if (!hasBG)
|
||||
return PR_FALSE;
|
||||
if (!bg->HasFixedBackground())
|
||||
return PR_FALSE;
|
||||
|
||||
// aAncestorFrame is the frame that is going to be moved.
|
||||
// Check if mFrame is equal to aAncestorFrame or aAncestorFrame is an
|
||||
// ancestor of mFrame in the same document. If this is true, mFrame
|
||||
nsIFrame* movingFrame = aBuilder->GetRootMovingFrame();
|
||||
// movingFrame is the frame that is going to be moved. It must be equal
|
||||
// to mFrame or some ancestor of mFrame, see assertion above.
|
||||
// If mFrame is in the same document as movingFrame, then mFrame
|
||||
// will move relative to its viewport, which means this display item will
|
||||
// change when it is moved. If they are in different documents, we do not
|
||||
// change when it is moved. If they are in different documents, we do not
|
||||
// want to return true because mFrame won't move relative to its viewport.
|
||||
return mFrame == aAncestorFrame ||
|
||||
nsLayoutUtils::IsProperAncestorFrame(aAncestorFrame, mFrame);
|
||||
return movingFrame->PresContext() == presContext;
|
||||
}
|
||||
|
||||
void
|
||||
@ -676,13 +679,13 @@ PRBool nsDisplayWrapList::IsUniform(nsDisplayListBuilder* aBuilder) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool nsDisplayWrapList::IsVaryingRelativeToFrame(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame) {
|
||||
for (nsDisplayItem* i = mList.GetBottom(); i != nsnull; i = i->GetAbove()) {
|
||||
if (i->IsVaryingRelativeToFrame(aBuilder, aFrame))
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
PRBool nsDisplayWrapList::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder) {
|
||||
// The only existing consumer of IsVaryingRelativeToMovingFrame is
|
||||
// nsLayoutUtils::ComputeRepaintRegionForCopy, which refrains from calling
|
||||
// this on wrapped lists.
|
||||
NS_WARNING("nsDisplayWrapList::IsVaryingRelativeToMovingFrame called unexpectedly");
|
||||
// We could try to do something but let's conservatively just return PR_TRUE.
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void nsDisplayWrapList::Paint(nsDisplayListBuilder* aBuilder,
|
||||
|
@ -133,7 +133,7 @@ public:
|
||||
* operation, we specify the scrolled frame as the moving frame.
|
||||
*/
|
||||
nsDisplayListBuilder(nsIFrame* aReferenceFrame, PRBool aIsForEvents,
|
||||
PRBool aBuildCaret, nsIFrame* aMovingFrame = nsnull);
|
||||
PRBool aBuildCaret);
|
||||
~nsDisplayListBuilder();
|
||||
|
||||
/**
|
||||
@ -154,14 +154,30 @@ public:
|
||||
* a new stacking context
|
||||
*/
|
||||
PRBool IsAtRootOfPseudoStackingContext() { return mIsAtRootOfPseudoStackingContext; }
|
||||
|
||||
/**
|
||||
* Indicate that we'll use this display list to analyze the effects
|
||||
* of aMovingFrame moving by aMoveDelta. The move has already been
|
||||
* applied to the frame tree.
|
||||
*/
|
||||
void SetMovingFrame(nsIFrame* aMovingFrame, const nsPoint& aMoveDelta) {
|
||||
mMovingFrame = aMovingFrame;
|
||||
mMoveDelta = aMoveDelta;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PR_TRUE if we are doing analysis of moving frames
|
||||
*/
|
||||
PRBool HasMovingFrames() { return mMovingFrame != nsnull; }
|
||||
/**
|
||||
* @return the frame that is being hypothetically moved
|
||||
* @return the frame that was moved
|
||||
*/
|
||||
nsIFrame* GetRootMovingFrame() { return mMovingFrame; }
|
||||
/**
|
||||
* @return the amount by which mMovingFrame was moved.
|
||||
* Only valid when GetRootMovingFrame() returns non-null.
|
||||
*/
|
||||
const nsPoint& GetMoveDelta() { return mMoveDelta; }
|
||||
/**
|
||||
* @return PR_TRUE if aFrame is, or is a descendant of, the hypothetical
|
||||
* moving frame
|
||||
@ -305,6 +321,7 @@ private:
|
||||
nsIFrame* mReferenceFrame;
|
||||
nsIFrame* mMovingFrame;
|
||||
nsIFrame* mIgnoreScrollFrame;
|
||||
nsPoint mMoveDelta; // only valid when mMovingFrame is non-null
|
||||
PLArenaPool mPool;
|
||||
nsCOMPtr<nsISelection> mBoundingSelection;
|
||||
nsAutoTArray<PresShellState,8> mPresShellStates;
|
||||
@ -426,11 +443,12 @@ public:
|
||||
virtual PRBool IsUniform(nsDisplayListBuilder* aBuilder) { return PR_FALSE; }
|
||||
/**
|
||||
* @return PR_FALSE if the painting performed by the item is invariant
|
||||
* when frame aFrame is moved relative to its parent (so it would be safe
|
||||
* to update the display by just copying pixels from their old to new location)
|
||||
* when frame aFrame is moved relative to aBuilder->GetRootMovingFrame().
|
||||
* This can only be called when aBuilder->IsMovingFrame(mFrame) is true.
|
||||
* It return PR_TRUE for all wrapped lists.
|
||||
*/
|
||||
virtual PRBool IsVaryingRelativeToFrame(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame) { return PR_FALSE; }
|
||||
virtual PRBool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder)
|
||||
{ return PR_FALSE; }
|
||||
/**
|
||||
* Actually paint this item to some rendering context.
|
||||
* @param aDirtyRect relative to aBuilder->ReferenceFrame()
|
||||
@ -996,8 +1014,7 @@ public:
|
||||
virtual nsIFrame* HitTest(nsDisplayListBuilder* aBuilder, nsPoint aPt,
|
||||
HitTestState* aState) { return mFrame; }
|
||||
virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder);
|
||||
virtual PRBool IsVaryingRelativeToFrame(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aAncestorFrame);
|
||||
virtual PRBool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder);
|
||||
virtual PRBool IsUniform(nsDisplayListBuilder* aBuilder);
|
||||
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
|
||||
virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx,
|
||||
@ -1080,8 +1097,7 @@ public:
|
||||
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
|
||||
virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder);
|
||||
virtual PRBool IsUniform(nsDisplayListBuilder* aBuilder);
|
||||
virtual PRBool IsVaryingRelativeToFrame(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame);
|
||||
virtual PRBool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder);
|
||||
virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx,
|
||||
const nsRect& aDirtyRect);
|
||||
virtual PRBool OptimizeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
|
@ -177,11 +177,14 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fprintf(aOutput, "%s %p(%s) (%d,%d,%d,%d)%s%s\n", i->Name(),
|
||||
fprintf(aOutput, "%s %p(%s) (%d,%d,%d,%d)%s%s%s%s\n", i->Name(),
|
||||
(void*)f, NS_ConvertUTF16toUTF8(fName).get(),
|
||||
rect.x, rect.y, rect.width, rect.height,
|
||||
i->IsOpaque(aBuilder) ? " opaque" : "",
|
||||
i->IsUniform(aBuilder) ? " uniform" : "");
|
||||
i->IsUniform(aBuilder) ? " uniform" : "",
|
||||
f && aBuilder->IsMovingFrame(f) ? " moving" : "",
|
||||
f && aBuilder->IsMovingFrame(f) && !i->GetList() &&
|
||||
i->IsVaryingRelativeToMovingFrame(aBuilder) ? " varying" : "");
|
||||
nsDisplayList* list = i->GetList();
|
||||
if (list) {
|
||||
PrintDisplayListTo(aBuilder, *list, aIndent + 4, aOutput);
|
||||
|
@ -1025,21 +1025,19 @@ AddItemsToRegion(nsDisplayListBuilder* aBuilder, nsDisplayList* aList,
|
||||
AddItemsToRegion(aBuilder, sublist, aRect, aClipRect, aDelta, aRegion);
|
||||
}
|
||||
} else {
|
||||
// Items left in the list are either IsVaryingRelativeToFrame
|
||||
// or !IsMovingFrame (i.e., not in the moving subtree)
|
||||
nsRect r;
|
||||
if (r.IntersectRect(aClipRect, item->GetBounds(aBuilder))) {
|
||||
PRBool inMovingSubtree = PR_FALSE;
|
||||
if (item->IsVaryingRelativeToFrame(aBuilder, aBuilder->GetRootMovingFrame())) {
|
||||
nsIFrame* f = item->GetUnderlyingFrame();
|
||||
NS_ASSERTION(f, "Must have an underlying frame for leaf item");
|
||||
inMovingSubtree = aBuilder->IsMovingFrame(f);
|
||||
AccumulateItemInRegion(aRegion, aRect + aDelta, r, item);
|
||||
}
|
||||
|
||||
if (!inMovingSubtree) {
|
||||
// if it's uniform and it includes both the old and new areas, then
|
||||
// we don't need to paint it
|
||||
nsIFrame* f = item->GetUnderlyingFrame();
|
||||
NS_ASSERTION(f, "Must have an underlying frame for leaf item");
|
||||
if (aBuilder->IsMovingFrame(f)) {
|
||||
if (item->IsVaryingRelativeToMovingFrame(aBuilder)) {
|
||||
// something like background-attachment:fixed that varies
|
||||
// its drawing when it moves
|
||||
AccumulateItemInRegion(aRegion, aRect + aDelta, r, item);
|
||||
}
|
||||
} else {
|
||||
// not moving. If it's uniform and it includes both the old and
|
||||
// new areas, then we don't need to paint it
|
||||
PRBool skip = r.Contains(aRect) && r.Contains(aRect + aDelta) &&
|
||||
item->IsUniform(aBuilder);
|
||||
if (!skip) {
|
||||
@ -1067,15 +1065,21 @@ nsLayoutUtils::ComputeRepaintRegionForCopy(nsIFrame* aRootFrame,
|
||||
"The root frame shouldn't be the one that's moving, that makes no sense");
|
||||
|
||||
// Build the 'after' display list over the whole area of interest.
|
||||
// Frames under aMovingFrame will not be allowed to affect (clip or cover)
|
||||
// non-moving frame display items ... then we can be sure the non-moving
|
||||
// frame display items we get are the same ones we would have gotten if
|
||||
// we had constructed the 'before' display list.
|
||||
// (We have to build the 'after' display list because the frame/view
|
||||
// hierarchy has already been updated for the move.)
|
||||
// hierarchy has already been updated for the move.
|
||||
// We need to ensure that the non-moving frame display items we get
|
||||
// are the same ones we would have gotten if we had constructed the
|
||||
// 'before' display list. So opaque moving items are only considered to
|
||||
// cover the intersection of their old and new bounds (see
|
||||
// nsDisplayItem::OptimizeVisibility). A moving clip item is not allowed
|
||||
// to clip non-moving items --- this is enforced by the code that sets
|
||||
// up nsDisplayClip items, in particular see ApplyAbsPosClipping.
|
||||
// XXX but currently a non-moving clip item can incorrectly clip
|
||||
// moving moving items! See bug 428156.
|
||||
nsRect rect;
|
||||
rect.UnionRect(aCopyRect, aCopyRect + aDelta);
|
||||
nsDisplayListBuilder builder(aRootFrame, PR_FALSE, PR_TRUE, aMovingFrame);
|
||||
nsDisplayListBuilder builder(aRootFrame, PR_FALSE, PR_TRUE);
|
||||
builder.SetMovingFrame(aMovingFrame, aDelta);
|
||||
nsDisplayList list;
|
||||
|
||||
builder.EnterPresShell(aRootFrame, rect);
|
||||
|
@ -419,9 +419,17 @@ public:
|
||||
*
|
||||
* This function assumes that the caller will do a bitblt copy of aCopyRect
|
||||
* to aCopyRect+aPt. It computes a region that must be repainted in order
|
||||
* for the resulting rendering to be correct.
|
||||
* for the resulting rendering to be correct. Frame geometry must have
|
||||
* already been adjusted for the scroll/copy operation.
|
||||
*
|
||||
* The region consists of:
|
||||
* Conceptually it works by computing a display list in the before-state
|
||||
* and a display list in the after-state and analyzing them to find the
|
||||
* differences. In practice it is only feasible to build a display list
|
||||
* in the after-state (plus building two display lists would be less
|
||||
* efficient), so we use some unfortunately tricky techniques to get by
|
||||
* with just the after-list.
|
||||
*
|
||||
* The output region consists of:
|
||||
* a) any visible background-attachment:fixed areas in the after-move display
|
||||
* list
|
||||
* b) any visible areas of the before-move display list corresponding to
|
||||
|
Loading…
Reference in New Issue
Block a user