Bug 976412. Part 1: Fix logic for determining when a display item can be placed in a layer. r=mattwoodrow

--HG--
extra : rebase_source : c390532cb3f6252fa388dfbe8176f4f911dfbdb3
This commit is contained in:
Robert O'Callahan 2014-02-26 17:17:18 +13:00
parent a139418d45
commit b8d068bc09

View File

@ -234,7 +234,9 @@ static inline MaskLayerImageCache* GetMaskLayerImageCache()
class ThebesLayerData {
public:
ThebesLayerData() :
mAnimatedGeometryRoot(nullptr), mReferenceFrame(nullptr),
mAnimatedGeometryRoot(nullptr),
mFixedPosFrameForLayerData(nullptr),
mReferenceFrame(nullptr),
mLayer(nullptr),
mIsSolidColorInVisibleRegion(false),
mSingleItemFixedToViewport(false),
@ -321,11 +323,16 @@ public:
mVisibleAboveRegion.SetEmpty();
}
bool IsBelow(const nsIntRect& aRect)
bool DrawAboveRegionIntersects(const nsIntRect& aRect)
{
return mAllDrawingAbove || mDrawAboveRegion.Intersects(aRect);
}
bool DrawRegionIntersects(const nsIntRect& aRect)
{
return IsSubjectToAsyncTransforms() || mDrawRegion.Intersects(aRect);
}
bool IntersectsVisibleAboveRegion(const nsIntRegion& aVisibleRegion)
{
if (mAllDrawingAbove) {
@ -339,6 +346,11 @@ public:
return true;
}
bool IsSubjectToAsyncTransforms()
{
return mFixedPosFrameForLayerData != nullptr;
}
/**
* The region of visible content in the layer, relative to the
* container layer (which is at the snapped top-left of the display
@ -375,6 +387,12 @@ public:
* active scrolled root.
*/
const nsIFrame* mAnimatedGeometryRoot;
/**
* If non-null, the frame from which we'll extract "fixed positioning"
* metadata for this layer. This can be a position:fixed frame or a viewport
* frame; the latter case is used for background-attachment:fixed content.
*/
const nsIFrame* mFixedPosFrameForLayerData;
const nsIFrame* mReferenceFrame;
ThebesLayer* mLayer;
/**
@ -620,10 +638,11 @@ protected:
* are directly on the viewport (e.g. background-attachment:fixed backgrounds).
*/
const nsIFrame* FindFixedPosFrameForLayerData(const nsIFrame* aAnimatedGeometryRoot,
bool aDisplayItemFixedToViewport,
const nsIntRegion& aDrawRegion,
nsIntRegion* aVisibleRegion,
bool* aIsSolidColorInVisibleRegion = nullptr);
bool aDisplayItemFixedToViewport);
void AdjustLayerDataForFixedPositioning(const nsIFrame* aFixedPosFrame,
const nsIntRegion& aDrawRegion,
nsIntRegion* aVisibleRegion,
bool* aIsSolidColorInVisibleRegion = nullptr);
/**
* Set fixed-pos layer metadata on aLayer according to the data for aFixedPosFrame.
*/
@ -1676,10 +1695,7 @@ ThebesLayerData::CanOptimizeImageLayer(nsDisplayListBuilder* aBuilder)
const nsIFrame*
ContainerState::FindFixedPosFrameForLayerData(const nsIFrame* aAnimatedGeometryRoot,
bool aDisplayItemFixedToViewport,
const nsIntRegion& aDrawRegion,
nsIntRegion* aVisibleRegion,
bool* aIsSolidColorInVisibleRegion)
bool aDisplayItemFixedToViewport)
{
if (!mManager->IsWidgetLayerManager()) {
// Never attach any fixed-pos metadata to inactive layers, it's pointless!
@ -1714,9 +1730,27 @@ ContainerState::FindFixedPosFrameForLayerData(const nsIFrame* aAnimatedGeometryR
return nullptr;
}
}
return result;
}
void
ContainerState::AdjustLayerDataForFixedPositioning(const nsIFrame* aFixedPosFrame,
const nsIntRegion& aDrawRegion,
nsIntRegion* aVisibleRegion,
bool* aIsSolidColorInVisibleRegion)
{
if (!aFixedPosFrame) {
return;
}
nsRect displayPort;
nsPresContext* presContext = aFixedPosFrame->PresContext();
DebugOnly<bool> hasDisplayPort =
nsLayoutUtils::ViewportHasDisplayPort(presContext, &displayPort);
NS_ASSERTION(hasDisplayPort, "No fixed-pos layer data if there's no displayport");
// Display ports are relative to the viewport, convert it to be relative
// to our reference frame.
nsIFrame* viewport = presContext->PresShell()->GetRootFrame();
displayPort += viewport->GetOffsetToCrossDoc(mContainerReferenceFrame);
nsIntRegion newVisibleRegion;
newVisibleRegion.And(ScaleToOutsidePixels(displayPort, false),
@ -1727,7 +1761,6 @@ ContainerState::FindFixedPosFrameForLayerData(const nsIFrame* aAnimatedGeometryR
}
*aVisibleRegion = newVisibleRegion;
}
return result;
}
void
@ -1804,12 +1837,10 @@ ContainerState::PopThebesLayerData()
int32_t lastIndex = mThebesLayerDataStack.Length() - 1;
ThebesLayerData* data = mThebesLayerDataStack[lastIndex];
const nsIFrame* fixedPosFrameForLayerData =
FindFixedPosFrameForLayerData(data->mAnimatedGeometryRoot,
data->mSingleItemFixedToViewport,
data->mDrawRegion,
&data->mVisibleRegion,
&data->mIsSolidColorInVisibleRegion);
AdjustLayerDataForFixedPositioning(data->mFixedPosFrameForLayerData,
data->mDrawRegion,
&data->mVisibleRegion,
&data->mIsSolidColorInVisibleRegion);
nsRefPtr<Layer> layer;
nsRefPtr<ImageContainer> imageContainer = data->CanOptimizeImageLayer(mBuilder);
@ -1935,7 +1966,7 @@ ContainerState::PopThebesLayerData()
}
layer->SetContentFlags(flags);
SetFixedPositionLayerData(layer, fixedPosFrameForLayerData);
SetFixedPositionLayerData(layer, data->mFixedPosFrameForLayerData);
ThebesLayerData* containingThebesLayerData =
mLayerBuilder->GetContainingThebesLayerData();
@ -2138,7 +2169,7 @@ ThebesLayerData::Accumulate(ContainerState* aState,
ThebesLayerData*
ContainerState::FindThebesLayerFor(nsDisplayItem* aItem,
const nsIntRect& aVisibleRect,
const nsIFrame* aActiveScrolledRoot,
const nsIFrame* aAnimatedGeometryRoot,
const nsPoint& aTopLeft,
bool aShouldFixToViewport)
{
@ -2146,31 +2177,39 @@ ContainerState::FindThebesLayerFor(nsDisplayItem* aItem,
int32_t lowestUsableLayerWithScrolledRoot = -1;
int32_t topmostLayerWithScrolledRoot = -1;
for (i = mThebesLayerDataStack.Length() - 1; i >= 0; --i) {
ThebesLayerData* data = mThebesLayerDataStack[i];
// ThebesLayers for items returning true from ShouldFixToViewport should
// not be added to (or have content moved below them),
// since they will receive special treatment for async scrolling.
// If the item is going to be fixed to the viewport, don't let it combine
// with any existing layer.
if (data->IsBelow(aVisibleRect) || data->mSingleItemFixedToViewport ||
aShouldFixToViewport) {
// Don't let should-fix-to-viewport items share a layer with any other items.
if (aShouldFixToViewport) {
++i;
break;
}
if (data->mAnimatedGeometryRoot == aActiveScrolledRoot) {
ThebesLayerData* data = mThebesLayerDataStack[i];
// Give up if there is content drawn above (in z-order) this layer that
// intersects aItem's visible region; aItem must be placed in a
// layer this layer.
if (data->DrawAboveRegionIntersects(aVisibleRect)) {
++i;
break;
}
// If the animated scrolled roots are the same and we can share this layer
// with the item, note this as a usable layer.
if (data->mAnimatedGeometryRoot == aAnimatedGeometryRoot &&
!data->mSingleItemFixedToViewport) {
lowestUsableLayerWithScrolledRoot = i;
if (topmostLayerWithScrolledRoot < 0) {
topmostLayerWithScrolledRoot = i;
}
}
if (data->mDrawRegion.Intersects(aVisibleRect))
// If the layer's drawn region intersects the item, stop now since no
// lower layer will be usable. Do the same if the layer is subject to
// async transforms, since we don't know where it will really be drawn.
if (data->DrawRegionIntersects(aVisibleRect))
break;
}
if (topmostLayerWithScrolledRoot < 0) {
--i;
for (; i >= 0; --i) {
ThebesLayerData* data = mThebesLayerDataStack[i];
if (data->mAnimatedGeometryRoot == aActiveScrolledRoot) {
if (data->mAnimatedGeometryRoot == aAnimatedGeometryRoot) {
topmostLayerWithScrolledRoot = i;
break;
}
@ -2186,12 +2225,14 @@ ContainerState::FindThebesLayerFor(nsDisplayItem* aItem,
ThebesLayerData* thebesLayerData = nullptr;
if (lowestUsableLayerWithScrolledRoot < 0) {
nsRefPtr<ThebesLayer> layer =
CreateOrRecycleThebesLayer(aActiveScrolledRoot, aItem->ReferenceFrame(), aTopLeft);
CreateOrRecycleThebesLayer(aAnimatedGeometryRoot, aItem->ReferenceFrame(), aTopLeft);
thebesLayerData = new ThebesLayerData();
mThebesLayerDataStack.AppendElement(thebesLayerData);
thebesLayerData->mLayer = layer;
thebesLayerData->mAnimatedGeometryRoot = aActiveScrolledRoot;
thebesLayerData->mAnimatedGeometryRoot = aAnimatedGeometryRoot;
thebesLayerData->mFixedPosFrameForLayerData =
FindFixedPosFrameForLayerData(aAnimatedGeometryRoot, aShouldFixToViewport);
thebesLayerData->mReferenceFrame = aItem->ReferenceFrame();
thebesLayerData->mSingleItemFixedToViewport = aShouldFixToViewport;
@ -2428,11 +2469,12 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
NS_ASSERTION(!ownLayer->AsThebesLayer(),
"Should never have created a dedicated Thebes layer!");
nsIntRegion visibleRegion(itemVisibleRect);
const nsIFrame* fixedPosFrame =
FindFixedPosFrameForLayerData(animatedGeometryRoot, shouldFixToViewport,
nsIntRegion(itemDrawRect), &visibleRegion);
FindFixedPosFrameForLayerData(animatedGeometryRoot, shouldFixToViewport);
if (fixedPosFrame) {
nsIntRegion visibleRegion(itemVisibleRect);
AdjustLayerDataForFixedPositioning(fixedPosFrame,
nsIntRegion(itemDrawRect), &visibleRegion);
itemVisibleRect = visibleRegion.GetBounds();
}
SetFixedPositionLayerData(ownLayer, fixedPosFrame);