--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -1056,17 +1056,17 @@ public:
mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
mContainerReferenceFrame =
const_cast<nsIFrame*>(aContainerItem ? aContainerItem->ReferenceFrameForChildren() :
mBuilder->FindReferenceFrameFor(mContainerFrame));
bool isAtRoot = !aContainerItem || (aContainerItem->Frame() == mBuilder->RootReferenceFrame());
MOZ_ASSERT_IF(isAtRoot, mContainerReferenceFrame == mBuilder->RootReferenceFrame());
mContainerAnimatedGeometryRoot = isAtRoot
? mContainerReferenceFrame
- : nsLayoutUtils::GetAnimatedGeometryRootFor(aContainerItem, aBuilder);
+ : aContainerItem->AnimatedGeometryRoot();
MOZ_ASSERT(!mBuilder->IsPaintingToWindow() ||
nsLayoutUtils::IsAncestorFrameCrossDoc(mBuilder->RootReferenceFrame(),
mContainerAnimatedGeometryRoot));
NS_ASSERTION(!aContainerItem || !aContainerItem->ShouldFixToViewport(mBuilder),
"Container items never return true for ShouldFixToViewport");
mContainerFixedPosFrame =
FindFixedPosFrameForLayerData(mContainerAnimatedGeometryRoot, false);
// When AllowResidualTranslation is false, display items will be drawn
@@ -3711,18 +3711,17 @@ ContainerState::ChooseAnimatedGeometryRo
// Don't use an item that won't be part of any PaintedLayers to pick the
// active scrolled root.
if (layerState == LAYER_ACTIVE_FORCE) {
continue;
}
// Try using the actual active scrolled root of the backmost item, as that
// should result in the least invalidation when scrolling.
- *aAnimatedGeometryRoot =
- nsLayoutUtils::GetAnimatedGeometryRootFor(item, mBuilder);
+ *aAnimatedGeometryRoot = item->AnimatedGeometryRoot();
return true;
}
return false;
}
nsIntRegion
ContainerState::ComputeOpaqueRect(nsDisplayItem* aItem,
const nsIFrame* aAnimatedGeometryRoot,
@@ -3887,18 +3886,17 @@ ContainerState::ProcessDisplayItems(nsDi
if (layerState == LAYER_INACTIVE &&
nsDisplayItem::ForceActiveLayers()) {
layerState = LAYER_ACTIVE;
}
bool forceInactive;
const nsIFrame* animatedGeometryRoot;
const nsIFrame* animatedGeometryRootForScrollMetadata = nullptr;
- const nsIFrame* realAnimatedGeometryRootOfItem =
- nsLayoutUtils::GetAnimatedGeometryRootFor(item, mBuilder);
+ const nsIFrame* realAnimatedGeometryRootOfItem = item->AnimatedGeometryRoot();
if (mFlattenToSingleLayer) {
forceInactive = true;
animatedGeometryRoot = lastAnimatedGeometryRoot;
} else {
forceInactive = false;
if (mManager->IsWidgetLayerManager()) {
animatedGeometryRoot = realAnimatedGeometryRootOfItem;
// Unlike GetAnimatedGeometryRootFor(), GetAnimatedGeometryRootForFrame() does not
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1991,21 +1991,27 @@ void nsDisplayList::SortByCSSOrder(nsDis
void nsDisplayList::Sort(nsDisplayListBuilder* aBuilder,
SortLEQ aCmp, void* aClosure) {
::Sort(this, Count(), aCmp, aClosure);
}
nsDisplayItem::nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
: mFrame(aFrame)
, mClip(aBuilder->ClipState().GetCurrentCombinedClip(aBuilder))
+ , mAnimatedGeometryRoot(nullptr)
#ifdef MOZ_DUMP_PAINTING
, mPainted(false)
#endif
{
mReferenceFrame = aBuilder->FindReferenceFrameFor(aFrame, &mToReferenceFrame);
+ // This can return the wrong result if the item override ShouldFixToViewport(),
+ // the item needs to set it again in its constructor.
+ mAnimatedGeometryRoot = nsLayoutUtils::GetAnimatedGeometryRootForInit(this, aBuilder);
+ MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(aBuilder->RootReferenceFrame(),
+ mAnimatedGeometryRoot), "Bad");
NS_ASSERTION(aBuilder->GetDirtyRect().width >= 0 ||
!aBuilder->IsForPainting(), "dirty rect not set");
// The dirty rect is for mCurrentFrame, so we have to use
// mCurrentOffsetToReferenceFrame
mVisibleRect = aBuilder->GetDirtyRect() +
aBuilder->GetCurrentFrameOffsetToReferenceFrame();
}
@@ -2136,16 +2142,19 @@ nsDisplayBackgroundImage::nsDisplayBackg
: nsDisplayImageContainer(aBuilder, aFrame)
, mBackgroundStyle(aBackgroundStyle)
, mLayer(aLayer)
{
MOZ_COUNT_CTOR(nsDisplayBackgroundImage);
mBounds = GetBoundsInternal(aBuilder);
mDestArea = GetDestAreaInternal(aBuilder);
+ if (ShouldFixToViewport(aBuilder)) {
+ mAnimatedGeometryRoot = nsLayoutUtils::GetAnimatedGeometryRootFor(this, aBuilder);
+ }
}
nsRect
nsDisplayBackgroundImage::GetDestAreaInternal(nsDisplayListBuilder* aBuilder)
{
if (!mBackgroundStyle) {
return nsRect();
}
@@ -3781,18 +3790,17 @@ RequiredLayerStateForChildren(nsDisplayL
LayerManager* aManager,
const ContainerLayerParameters& aParameters,
const nsDisplayList& aList,
nsIFrame* aExpectedAnimatedGeometryRootForChildren)
{
LayerState result = LAYER_INACTIVE;
for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) {
if (result == LAYER_INACTIVE &&
- nsLayoutUtils::GetAnimatedGeometryRootFor(i, aBuilder) !=
- aExpectedAnimatedGeometryRootForChildren) {
+ i->AnimatedGeometryRoot() != aExpectedAnimatedGeometryRootForChildren) {
result = LAYER_ACTIVE;
}
LayerState state = i->GetLayerState(aBuilder, aManager, aParameters);
if ((state == LAYER_ACTIVE || state == LAYER_ACTIVE_FORCE) &&
state > result) {
result = state;
}
@@ -4056,18 +4064,17 @@ nsDisplayOpacity::GetLayerState(nsDispla
if (mForEventsOnly) {
MOZ_ASSERT(mOpacity == 0);
return LAYER_INACTIVE;
}
if (NeedsActiveLayer(aBuilder))
return LAYER_ACTIVE;
- return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList,
- nsLayoutUtils::GetAnimatedGeometryRootFor(this, aBuilder));
+ return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList, AnimatedGeometryRoot());
}
bool
nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion) {
// Our children are translucent so we should not allow them to subtract
// area from aVisibleRegion. We do need to find out what is visible under
// our children in the temporary compositing buffer, because if our children
@@ -4789,16 +4796,17 @@ nsDisplayTransform::SetReferenceFrameToA
{
if (mFrame == aBuilder->RootReferenceFrame()) {
return;
}
nsIFrame *outerFrame = nsLayoutUtils::GetCrossDocParentFrame(mFrame);
mReferenceFrame =
aBuilder->FindReferenceFrameFor(outerFrame);
mToReferenceFrame = mFrame->GetOffsetToCrossDoc(mReferenceFrame);
+ mAnimatedGeometryRoot = nsLayoutUtils::GetAnimatedGeometryRootForFrame(aBuilder, outerFrame);
mVisibleRect = aBuilder->GetDirtyRect() + mToReferenceFrame;
}
void
nsDisplayTransform::Init(nsDisplayListBuilder* aBuilder)
{
mHasBounds = false;
mStoredList.SetClip(aBuilder, DisplayItemClip::NoClip());
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -1226,16 +1226,17 @@ public:
/**
* This constructor is only used in rare cases when we need to construct
* temporary items.
*/
explicit nsDisplayItem(nsIFrame* aFrame)
: mFrame(aFrame)
, mClip(nullptr)
, mReferenceFrame(nullptr)
+ , mAnimatedGeometryRoot(nullptr)
#ifdef MOZ_DUMP_PAINTING
, mPainted(false)
#endif
{
}
virtual ~nsDisplayItem() {}
void* operator new(size_t aSize,
@@ -1687,16 +1688,21 @@ public:
*/
const nsIFrame* ReferenceFrame() const { return mReferenceFrame; }
/**
* Returns the reference frame for display item children of this item.
*/
virtual const nsIFrame* ReferenceFrameForChildren() const { return mReferenceFrame; }
+ nsIFrame* AnimatedGeometryRoot() const {
+ MOZ_ASSERT(mAnimatedGeometryRoot, "Must have cached AGR before accessing it!");
+ return mAnimatedGeometryRoot;
+ }
+
/**
* Checks if this display item (or any children) contains content that might
* be rendered with component alpha (e.g. subpixel antialiasing). Returns the
* bounds of the area that needs component alpha, or an empty rect if nothing
* in the item does.
*/
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) { return nsRect(); }
@@ -1746,16 +1752,17 @@ protected:
friend class nsDisplayList;
nsDisplayItem() { mAbove = nullptr; }
nsIFrame* mFrame;
const DisplayItemClip* mClip;
// Result of FindReferenceFrameFor(mFrame), if mFrame is non-null
const nsIFrame* mReferenceFrame;
+ nsIFrame* mAnimatedGeometryRoot;
// Result of ToReferenceFrame(mFrame), if mFrame is non-null
nsPoint mToReferenceFrame;
// This is the rectangle that needs to be painted.
// Display item construction sets this to the dirty rect.
// nsDisplayList::ComputeVisibility sets this to the visible region
// of the item by intersecting the current visible region with the bounds
// of the item. Paint implementations can use this to limit their drawing.
// Guaranteed to be contained in GetBounds().
--- a/layout/base/nsLayoutDebugger.cpp
+++ b/layout/base/nsLayoutDebugger.cpp
@@ -157,42 +157,41 @@ PrintDisplayItemTo(nsDisplayListBuilder*
if (content->GetClasses()) {
content->GetClasses()->ToString(tmp);
contentData.AppendLiteral(" class:");
contentData.Append(tmp);
}
}
bool snap;
nsRect rect = aItem->GetBounds(aBuilder, &snap);
- nsRect layerRect = rect -
- nsLayoutUtils::GetAnimatedGeometryRootFor(aItem, aBuilder)->
- GetOffsetToCrossDoc(aItem->ReferenceFrame());
+ nsRect layerRect = rect - aItem->AnimatedGeometryRoot()->GetOffsetToCrossDoc(aItem->ReferenceFrame());
nscolor color;
nsRect vis = aItem->GetVisibleRect();
nsRect component = aItem->GetComponentAlphaBounds(aBuilder);
nsDisplayList* list = aItem->GetChildren();
const DisplayItemClip& clip = aItem->GetClip();
nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap);
#ifdef MOZ_DUMP_PAINTING
if (aDumpHtml && aItem->Painted()) {
nsCString string(aItem->Name());
string.Append('-');
string.AppendInt((uint64_t)aItem);
aStream << nsPrintfCString("<a href=\"javascript:ViewImage('%s')\">", string.BeginReading());
}
#endif
- aStream << nsPrintfCString("%s p=0x%p f=0x%p(%s) %sbounds(%d,%d,%d,%d) layerBounds(%d,%d,%d,%d) visible(%d,%d,%d,%d) componentAlpha(%d,%d,%d,%d) clip(%s) %s",
+ aStream << nsPrintfCString("%s p=0x%p f=0x%p(%s) %sbounds(%d,%d,%d,%d) layerBounds(%d,%d,%d,%d) visible(%d,%d,%d,%d) componentAlpha(%d,%d,%d,%d) clip(%s) %s ref=0x%p agr=0x%p",
aItem->Name(), aItem, (void*)f, NS_ConvertUTF16toUTF8(contentData).get(),
(aItem->ZIndex() ? nsPrintfCString("z=%d ", aItem->ZIndex()).get() : ""),
rect.x, rect.y, rect.width, rect.height,
layerRect.x, layerRect.y, layerRect.width, layerRect.height,
vis.x, vis.y, vis.width, vis.height,
component.x, component.y, component.width, component.height,
clip.ToString().get(),
- aItem->IsUniform(aBuilder, &color) ? " uniform" : "");
+ aItem->IsUniform(aBuilder, &color) ? " uniform" : "",
+ aItem->ReferenceFrame(), aItem->AnimatedGeometryRoot());
nsRegionRectIterator iter(opaque);
for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
aStream << nsPrintfCString(" (opaque %d,%d,%d,%d)", r->x, r->y, r->width, r->height);
}
if (aItem->ShouldFixToViewport(aBuilder)) {
aStream << " fixed";
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1956,16 +1956,35 @@ nsLayoutUtils::GetAnimatedGeometryRootFo
nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(f);
if (parent) {
return GetAnimatedGeometryRootForFrame(aBuilder, parent);
}
}
return GetAnimatedGeometryRootForFrame(aBuilder, f);
}
+nsIFrame*
+nsLayoutUtils::GetAnimatedGeometryRootForInit(nsDisplayItem* aItem,
+ nsDisplayListBuilder* aBuilder)
+{
+ nsIFrame* f = aItem->Frame();
+ if (aItem->ShouldFixToViewport(aBuilder)) {
+ // 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
+ // nsGfxScrollFrame will not repaint this item when scrolling occurs.
+ nsIFrame* viewportFrame =
+ nsLayoutUtils::GetClosestFrameOfType(f, nsGkAtoms::viewportFrame, aBuilder->RootReferenceFrame());
+ if (viewportFrame) {
+ return GetAnimatedGeometryRootForFrame(aBuilder, viewportFrame);
+ }
+ }
+ return GetAnimatedGeometryRootForFrame(aBuilder, f);
+}
+
// static
nsIScrollableFrame*
nsLayoutUtils::GetNearestScrollableFrameForDirection(nsIFrame* aFrame,
Direction aDirection)
{
NS_ASSERTION(aFrame, "GetNearestScrollableFrameForDirection expects a non-null frame");
for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
nsIScrollableFrame* scrollableFrame = do_QueryFrame(f);
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -558,16 +558,23 @@ public:
* do not do any special processing for background attachment fixed items,
* instead treating them like any other frame.
*/
AGR_IGNORE_BACKGROUND_ATTACHMENT_FIXED = 0x01
};
static nsIFrame* GetAnimatedGeometryRootFor(nsDisplayItem* aItem,
nsDisplayListBuilder* aBuilder,
uint32_t aFlags = 0);
+ /**
+ * Version of GetAnimatedGeometryRootFor that can be called in nsDisplayItem
+ * constructor, and only from there. Not valid for transform items, but they
+ * set their AGR in their constructor.
+ */
+ static nsIFrame* GetAnimatedGeometryRootForInit(nsDisplayItem* aItem,
+ nsDisplayListBuilder* aBuilder);
/**
* Finds the nearest ancestor frame to aFrame that is considered to have (or
* will have) "animated geometry". This could be aFrame.
*/
static nsIFrame* GetAnimatedGeometryRootForFrame(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame);
--- a/layout/generic/nsCanvasFrame.h
+++ b/layout/generic/nsCanvasFrame.h
@@ -234,17 +234,21 @@ public:
#endif
};
class nsDisplayCanvasBackgroundImage : public nsDisplayBackgroundImage {
public:
nsDisplayCanvasBackgroundImage(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
uint32_t aLayer, const nsStyleBackground* aBg)
: nsDisplayBackgroundImage(aBuilder, aFrame, aLayer, aBg)
- {}
+ {
+ if (ShouldFixToViewport(aBuilder)) {
+ mAnimatedGeometryRoot = nsLayoutUtils::GetAnimatedGeometryRootFor(this, aBuilder);
+ }
+ }
virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override;
virtual void NotifyRenderingChanged() override
{
mFrame->Properties().Delete(nsIFrame::CachedBackgroundImage());
mFrame->Properties().Delete(nsIFrame::CachedBackgroundImageDT());
}