Bug 653133 - Fennec crashes when loading a page with huge background-attachment:fixed background r=roc

This commit is contained in:
Tatiana Meshkova 2011-05-09 11:40:09 +03:00
parent 36c1d2725f
commit 52765d2b7e
4 changed files with 77 additions and 32 deletions

View File

@ -138,20 +138,22 @@ static PRBool IsFixedFrame(nsIFrame* aFrame)
return aFrame && aFrame->GetParent() && !aFrame->GetParent()->GetParent();
}
static PRBool IsFixedItem(nsDisplayItem *aItem, nsDisplayListBuilder* aBuilder)
static PRBool IsFixedItem(nsDisplayItem *aItem, nsDisplayListBuilder* aBuilder,
PRBool* aIsFixedBackground)
{
nsIFrame* activeScrolledRoot =
nsLayoutUtils::GetActiveScrolledRootFor(aItem, aBuilder);
nsLayoutUtils::GetActiveScrolledRootFor(aItem, aBuilder, aIsFixedBackground);
return activeScrolledRoot &&
!nsLayoutUtils::ScrolledByViewportScrolling(activeScrolledRoot,
aBuilder);
}
static PRBool ForceVisiblityForFixedItem(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem)
nsDisplayItem* aItem,
PRBool* aIsFixedBackground)
{
return aBuilder->GetHasDisplayPort() && aBuilder->GetHasFixedItems() &&
IsFixedItem(aItem, aBuilder);
return aBuilder->GetDisplayPort() && aBuilder->GetHasFixedItems() &&
IsFixedItem(aItem, aBuilder, aIsFixedBackground);
}
void nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame,
@ -434,6 +436,26 @@ TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder,
return opaque;
}
static nsRect GetDisplayPortBounds(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem,
PRBool aIgnoreTransform)
{
nsIFrame* frame = aItem->GetUnderlyingFrame();
nscoord auPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel();
gfxMatrix transform;
if (!aIgnoreTransform) {
transform = nsLayoutUtils::GetTransformToAncestor(frame,
aBuilder->ReferenceFrame());
transform.Invert();
}
const nsRect* displayport = aBuilder->GetDisplayPort();
return nsLayoutUtils::MatrixTransformRect(
nsRect(0, 0, displayport->width, displayport->height),
transform, auPerDevPixel);
}
PRBool
nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion,
@ -477,12 +499,13 @@ nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
nsRect bounds = item->GetBounds(aBuilder);
nsRegion itemVisible;
itemVisible.And(*aVisibleRegion, bounds);
item->mVisibleRect = itemVisible.GetBounds();
if (ForceVisiblityForFixedItem(aBuilder, item)) {
item->mVisibleRect = bounds;
PRBool isFixedBackground;
if (ForceVisiblityForFixedItem(aBuilder, item, &isFixedBackground)) {
itemVisible.And(GetDisplayPortBounds(aBuilder, item, isFixedBackground), bounds);
} else {
itemVisible.And(*aVisibleRegion, bounds);
}
item->mVisibleRect = itemVisible.GetBounds();
PRBool containsRootContentDocBG = PR_FALSE;
if (item->ComputeVisibility(aBuilder, aVisibleRegion, aAllowVisibleRegionExpansion,
@ -808,12 +831,13 @@ PRBool nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder,
nsRect bounds = GetBounds(aBuilder);
nsRegion itemVisible;
itemVisible.And(*aVisibleRegion, bounds);
mVisibleRect = itemVisible.GetBounds();
if (ForceVisiblityForFixedItem(aBuilder, this)) {
mVisibleRect = bounds;
PRBool isFixedBackground;
if (ForceVisiblityForFixedItem(aBuilder, this, &isFixedBackground)) {
itemVisible.And(GetDisplayPortBounds(aBuilder, this, isFixedBackground), bounds);
} else {
itemVisible.And(*aVisibleRegion, bounds);
}
mVisibleRect = itemVisible.GetBounds();
// When we recompute visibility within layers we don't need to
// expand the visible region for content behind plugins (the plugin

View File

@ -295,8 +295,11 @@ public:
/**
* Call this if using display port for scrolling.
*/
void SetHasDisplayPort() { mHasDisplayPort = PR_TRUE; }
PRBool GetHasDisplayPort() { return mHasDisplayPort; }
void SetDisplayPort(const nsRect& aDisplayPort) {
mHasDisplayPort = PR_TRUE;
mDisplayPort = aDisplayPort;
}
const nsRect* GetDisplayPort() { return mHasDisplayPort ? &mDisplayPort : nsnull; }
/**
* Call this if ReferenceFrame() is a viewport frame with fixed-position
@ -510,6 +513,7 @@ private:
PRPackedBool mIsPaintingToWindow;
PRPackedBool mSnappingEnabled;
PRPackedBool mHasDisplayPort;
nsRect mDisplayPort;
PRPackedBool mHasFixedItems;
};

View File

@ -786,13 +786,20 @@ nsLayoutUtils::GetActiveScrolledRootFor(nsIFrame* aFrame,
nsIFrame*
nsLayoutUtils::GetActiveScrolledRootFor(nsDisplayItem* aItem,
nsDisplayListBuilder* aBuilder)
nsDisplayListBuilder* aBuilder,
PRBool* aShouldFixToViewport)
{
nsIFrame* f = aItem->GetUnderlyingFrame();
if (aShouldFixToViewport) {
*aShouldFixToViewport = PR_FALSE;
}
if (!f) {
return nsnull;
}
if (aItem->ShouldFixToViewport(aBuilder)) {
if (aShouldFixToViewport) {
*aShouldFixToViewport = PR_TRUE;
}
// Make its active scrolled root be the active scrolled root of
// the enclosing viewport, since it shouldn't be scrolled by scrolled
// frames in its document. InvalidateFixedBackgroundFramesFromList in
@ -1087,24 +1094,21 @@ nsLayoutUtils::MatrixTransformPoint(const nsPoint &aPoint,
NSFloatPixelsToAppUnits(float(image.y), aFactor));
}
/**
* Returns the CTM at the specified frame.
*
* @param aFrame The frame at which we should calculate the CTM.
* @return The CTM at the specified frame.
*/
static gfxMatrix GetCTMAt(nsIFrame *aFrame)
gfxMatrix nsLayoutUtils::GetTransformToAncestor(nsIFrame *aFrame,
nsIFrame* aStopAtAncestor)
{
gfxMatrix ctm;
/* Starting at the specified frame, we'll use the GetTransformMatrix
* function of the frame, which gives us a matrix from this frame up
* to some other ancestor frame. Once this function returns null,
* we've hit the top of the frame tree and can stop. We get the CTM
* by simply accumulating all of these matrices together.
* to some other ancestor frame. If aStopAtAncestor frame is not reached,
* we stop at root. We get the CTM by simply accumulating all of these
* matrices together.
*/
while (aFrame)
while (aFrame && aFrame != aStopAtAncestor) {
ctm *= aFrame->GetTransformMatrix(&aFrame);
}
NS_ASSERTION(aFrame == aStopAtAncestor, "How did we manage to miss the ancestor?");
return ctm;
}
@ -1117,7 +1121,7 @@ nsLayoutUtils::InvertTransformsToRoot(nsIFrame *aFrame,
/* To invert everything to the root, we'll get the CTM, invert it, and use it to transform
* the point.
*/
gfxMatrix ctm = GetCTMAt(aFrame);
gfxMatrix ctm = GetTransformToAncestor(aFrame);
/* If the ctm is singular, hand back (0, 0) as a sentinel. */
if (ctm.IsSingular())
@ -1447,7 +1451,7 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
nsDisplayListBuilder builder(aFrame, nsDisplayListBuilder::PAINTING,
!(aFlags & PAINT_HIDE_CARET));
if (usingDisplayPort) {
builder.SetHasDisplayPort();
builder.SetDisplayPort(displayport);
}
nsDisplayList list;

View File

@ -330,7 +330,8 @@ public:
nsIFrame* aStopAtAncestor);
static nsIFrame* GetActiveScrolledRootFor(nsDisplayItem* aItem,
nsDisplayListBuilder* aBuilder);
nsDisplayListBuilder* aBuilder,
PRBool* aShouldFixToViewport = nsnull);
static PRBool ScrolledByViewportScrolling(nsIFrame* aActiveScrolledRoot,
nsDisplayListBuilder* aBuilder);
@ -508,6 +509,18 @@ public:
PRBool aShouldIgnoreSuppression = PR_FALSE,
PRBool aIgnoreRootScrollFrame = PR_FALSE);
/**
* Returns the CTM at the specified frame. This matrix can be used to map
* coordinates from aFrame's to aStopAtAncestor's coordinate system.
*
* @param aFrame The frame at which we should calculate the CTM.
* @param aStopAtAncestor is an ancestor frame to stop at. If it's nsnull,
* matrix accumulating stops at root.
* @return The CTM at the specified frame.
*/
static gfxMatrix GetTransformToAncestor(nsIFrame *aFrame,
nsIFrame* aStopAtAncestor = nsnull);
/**
* Given a point in the global coordinate space, returns that point expressed
* in the coordinate system of aFrame. This effectively inverts all transforms