--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -229,17 +229,19 @@ static inline MaskLayerImageCache* GetMa
* assign display items to existing ThebesLayers, and to the lowest
* ThebesLayer in z-order. This reduces the number of layers and
* makes it more likely a display item will be rendered to an opaque
* layer, giving us the best chance of getting subpixel AA.
*/
class ThebesLayerData {
public:
ThebesLayerData() :
- mAnimatedGeometryRoot(nullptr), mReferenceFrame(nullptr),
+ mAnimatedGeometryRoot(nullptr),
+ mFixedPosFrameForLayerData(nullptr),
+ mReferenceFrame(nullptr),
mLayer(nullptr),
mIsSolidColorInVisibleRegion(false),
mSingleItemFixedToViewport(false),
mNeedComponentAlpha(false),
mForceTransparentSurface(false),
mImage(nullptr),
mCommonClipCount(-1),
mAllDrawingAbove(false)
@@ -316,34 +318,44 @@ public:
void SetAllDrawingAbove()
{
mAllDrawingAbove = true;
mDrawAboveRegion.SetEmpty();
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) {
return true;
}
nsIntRegion visibleAboveIntersection;
visibleAboveIntersection.And(mVisibleAboveRegion, aVisibleRegion);
if (visibleAboveIntersection.IsEmpty()) {
return false;
}
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
* list reference frame).
*/
nsIntRegion mVisibleRegion;
/**
* The region containing the bounds of all display items in the layer,
@@ -370,16 +382,22 @@ public:
*/
nsIntRegion mDispatchToContentHitRegion;
/**
* The "active scrolled root" for all content in the layer. Must
* be non-null; all content in a ThebesLayer must have the same
* 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;
/**
* If mIsSolidColorInVisibleRegion is true, this is the color of the visible
* region.
*/
nscolor mSolidColor;
/**
@@ -615,20 +633,21 @@ protected:
* aDrawRegion and the displayport, and updates *aIsSolidColorInVisibleRegion
* (if non-null) to false if the visible region grows.
* aDisplayItemFixedToViewport is true if the layer contains a single display
* item which returned true for ShouldFixToViewport.
* This can return the actual viewport frame for layers whose display items
* 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.
*/
void SetFixedPositionLayerData(Layer* aLayer,
const nsIFrame* aFixedPosFrame);
/**
* Indicate that we are done adding items to the ThebesLayer at the top of
* mThebesLayerDataStack. Set the final visible region and opaque-content
@@ -1671,20 +1690,17 @@ ThebesLayerData::CanOptimizeImageLayer(n
return nullptr;
}
return mImage->GetContainer(mLayer->Manager(), 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!
return nullptr;
}
nsPresContext* presContext = mContainerFrame->PresContext();
nsIFrame* viewport = presContext->PresShell()->GetRootFrame();
@@ -1709,30 +1725,47 @@ ContainerState::FindFixedPosFrameForLaye
// The metadata will go on an ancestor layer if necessary.
return nullptr;
}
}
if (!result) {
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),
aDrawRegion);
if (!aVisibleRegion->Contains(newVisibleRegion)) {
if (aIsSolidColorInVisibleRegion) {
*aIsSolidColorInVisibleRegion = false;
}
*aVisibleRegion = newVisibleRegion;
}
- return result;
}
void
ContainerState::SetFixedPositionLayerData(Layer* aLayer,
const nsIFrame* aFixedPosFrame)
{
aLayer->SetIsFixedPosition(aFixedPosFrame != nullptr);
if (!aFixedPosFrame) {
@@ -1799,22 +1832,20 @@ AddTransformedBoundsToRegion(const nsInt
void
ContainerState::PopThebesLayerData()
{
NS_ASSERTION(!mThebesLayerDataStack.IsEmpty(), "Can't pop");
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);
if ((data->mIsSolidColorInVisibleRegion || imageContainer) &&
(data->mLayer->GetValidRegion().IsEmpty() || mLayerBuilder->CheckInLayerTreeCompressionMode())) {
NS_ASSERTION(!(data->mIsSolidColorInVisibleRegion && imageContainer),
"Can't be a solid color as well as an image!");
if (imageContainer) {
@@ -1930,17 +1961,17 @@ ContainerState::PopThebesLayerData()
}
if (isOpaque && !data->mForceTransparentSurface) {
flags |= Layer::CONTENT_OPAQUE;
} else if (data->mNeedComponentAlpha && !hidpi) {
flags |= Layer::CONTENT_COMPONENT_ALPHA;
}
layer->SetContentFlags(flags);
- SetFixedPositionLayerData(layer, fixedPosFrameForLayerData);
+ SetFixedPositionLayerData(layer, data->mFixedPosFrameForLayerData);
ThebesLayerData* containingThebesLayerData =
mLayerBuilder->GetContainingThebesLayerData();
if (containingThebesLayerData) {
gfx3DMatrix matrix = GetTransformToRoot(layer);
nsIntPoint translatedDest = GetTranslationForThebesLayer(containingThebesLayerData->mLayer);
matrix.TranslatePost(-gfxPoint3D(translatedDest.x, translatedDest.y, 0));
AddTransformedBoundsToRegion(data->mDispatchToContentHitRegion, matrix,
@@ -2133,70 +2164,80 @@ ThebesLayerData::Accumulate(ContainerSta
}
}
}
}
ThebesLayerData*
ContainerState::FindThebesLayerFor(nsDisplayItem* aItem,
const nsIntRect& aVisibleRect,
- const nsIFrame* aActiveScrolledRoot,
+ const nsIFrame* aAnimatedGeometryRoot,
const nsPoint& aTopLeft,
bool aShouldFixToViewport)
{
int32_t i;
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;
}
}
}
if (topmostLayerWithScrolledRoot >= 0) {
while (uint32_t(topmostLayerWithScrolledRoot + 1) < mThebesLayerDataStack.Length()) {
PopThebesLayerData();
}
}
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;
NS_ASSERTION(!mNewChildLayers.Contains(layer), "Layer already in list???");
*mNewChildLayers.AppendElement() = layer.forget();
} else {
thebesLayerData = mThebesLayerDataStack[lowestUsableLayerWithScrolledRoot];
}
@@ -2423,21 +2464,22 @@ ContainerState::ProcessDisplayItems(cons
nsRefPtr<Layer> ownLayer = item->BuildLayer(mBuilder, mManager, mParameters);
if (!ownLayer) {
continue;
}
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);
nsRect invalid;
if (item->IsInvalid(invalid)) {
ownLayer->SetInvalidRectToVisibleRegion();
}