Bug 1298218 - Add a workaround for root scroll frame container layer scrolling. r?tnikkel
Root frame containers really throw a wrench into the whole system.
MozReview-Commit-ID: 9066vWMYxxr
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3287,37 +3287,49 @@ ScrollFrameHelper::BuildDisplayList(nsDi
// they're not scrolled with the rest of the document. But when both
// scrollbars are visible, the layer's visible rectangle would be the size
// of the viewport, so most layer implementations would create a layer buffer
// that's much larger than necessary. Creating independent layers for each
// scrollbar works around the problem.
bool createLayersForScrollbars = mIsRoot &&
mOuter->PresContext()->IsRootContentDocument();
+ nsIScrollableFrame* sf = do_QueryFrame(mOuter);
+ MOZ_ASSERT(sf);
+
if (ignoringThisScrollFrame) {
// Root scrollframes have FrameMetrics and clipping on their container
// layers, so don't apply clipping again.
mAddClipRectToLayer = false;
// If we are a root scroll frame that has a display port we want to add
// scrollbars, they will be children of the scrollable layer, but they get
// adjusted by the APZC automatically.
bool addScrollBars = mIsRoot && usingDisplayPort && !aBuilder->IsForEventDelivery();
if (addScrollBars) {
// Add classic scrollbars.
AppendScrollPartsTo(aBuilder, aDirtyRect, aLists,
createLayersForScrollbars, false);
}
- // Don't clip the scrolled child, and don't paint scrollbars/scrollcorner.
- // The scrolled frame shouldn't have its own background/border, so we
- // can just pass aLists directly.
- mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame,
- dirtyRect, aLists);
+ {
+ nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
+ if (aBuilder->IsPaintingToWindow() &&
+ gfxPrefs::LayoutUseContainersForRootFrames() && mIsRoot) {
+ asrSetter.EnterScrollFrame(sf);
+ aBuilder->SetActiveScrolledRootForRootScrollframe(aBuilder->CurrentActiveScrolledRoot());
+ }
+
+ // Don't clip the scrolled child, and don't paint scrollbars/scrollcorner.
+ // The scrolled frame shouldn't have its own background/border, so we
+ // can just pass aLists directly.
+ mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame,
+ dirtyRect, aLists);
+ }
if (addScrollBars) {
// Add overlay scrollbars.
AppendScrollPartsTo(aBuilder, aDirtyRect, aLists,
createLayersForScrollbars, true);
}
return;
@@ -3392,19 +3404,16 @@ ScrollFrameHelper::BuildDisplayList(nsDi
// caret height on the top, and its full width on the right.
nsRect inflatedClip = clipRect;
inflatedClip.Inflate(nsMargin(caretRect.height / 2, caretRect.width, 0, 0));
contentBoxClip = Some(inflatedClip);
}
}
}
- nsIScrollableFrame* sf = do_QueryFrame(mOuter);
- MOZ_ASSERT(sf);
-
nsDisplayListCollection scrolledContent;
{
// Note that setting the current scroll parent id here means that positioned children
// of this scroll info layer will pick up the scroll info layer as their scroll handoff
// parent. This is intentional because that is what happens for positioned children
// of scroll layers, and we want to maintain consistent behaviour between scroll layers
// and scroll info layers.
nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(
@@ -3444,16 +3453,20 @@ ScrollFrameHelper::BuildDisplayList(nsDi
}
}
nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
if (mWillBuildScrollableLayer) {
asrSetter.EnterScrollFrame(sf);
}
+ if (mIsScrollableLayerInRootContainer) {
+ aBuilder->SetActiveScrolledRootForRootScrollframe(aBuilder->CurrentActiveScrolledRoot());
+ }
+
{
// Clip our contents to the unsnapped scrolled rect. This makes sure that
// we don't have display items over the subpixel seam at the edge of the
// scrolled area.
DisplayListClipState::AutoSaveRestore scrolledRectClipState(aBuilder);
nsRect scrolledRectClip =
GetUnsnappedScrolledRectInternal(mScrolledFrame->GetScrollableOverflowRect(),
mScrollPort.Size()) + mScrolledFrame->GetPosition();
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -4079,17 +4079,18 @@ ContainerState::ProcessDisplayItems(nsDi
bounds = item->GetBounds(mBuilder, &dummy);
if (itemClip.HasClip()) {
bounds.IntersectRect(bounds, itemClip.GetClipRect());
}
}
if (!bounds.IsEmpty()) {
if (itemASR != mContainerASR) {
const DisplayItemClip* clip = DisplayItemClipChain::ClipForASR(item->GetClipChain(), mContainerASR);
- MOZ_ASSERT(clip, "the item should have finite bounds with respect to mContainerASR.");
+ MOZ_ASSERT(clip || gfxPrefs::LayoutUseContainersForRootFrames(),
+ "the item should have finite bounds with respect to mContainerASR.");
if (clip) {
bounds = clip->GetClipRect();
}
}
}
((nsRect&)mAccumulatedChildBounds).UnionRect(mAccumulatedChildBounds, bounds);
#endif
@@ -5569,16 +5570,22 @@ FrameLayerBuilder::BuildContainerLayerFo
NS_ASSERTION(aChildren->IsEmpty(), "Should have no children");
return containerLayer.forget();
}
const ActiveScrolledRoot* containerASR = aContainerItem ? aContainerItem->GetActiveScrolledRoot() : nullptr;
const ActiveScrolledRoot* containerScrollMetadataASR = aParameters.mScrollMetadataASR;
const ActiveScrolledRoot* containerCompositorASR = aParameters.mCompositorASR;
+ if (!aContainerItem && gfxPrefs::LayoutUseContainersForRootFrames()) {
+ containerASR = aBuilder->ActiveScrolledRootForRootScrollframe();
+ containerScrollMetadataASR = containerASR;
+ containerCompositorASR = containerASR;
+ }
+
ContainerLayerParameters scaleParameters;
nsRect bounds = aChildren->GetClippedBoundsWithRespectToASR(aBuilder, containerASR);
nsRect childrenVisible =
aContainerItem ? aContainerItem->GetVisibleRectForChildren() :
aContainerFrame->GetVisualOverflowRectRelativeToSelf();
if (!ChooseScaleAndSetTransform(this, aBuilder, aContainerFrame,
aContainerItem,
bounds.Intersect(childrenVisible),
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -860,16 +860,17 @@ nsDisplayListBuilder::nsDisplayListBuild
mCurrentFrame(aReferenceFrame),
mCurrentReferenceFrame(aReferenceFrame),
mCurrentAGR(&mRootAGR),
mRootAGR(aReferenceFrame, nullptr),
mUsedAGRBudget(0),
mDirtyRect(-1,-1,-1,-1),
mGlassDisplayItem(nullptr),
mScrollInfoItemsForHoisting(nullptr),
+ mActiveScrolledRootForRootScrollframe(nullptr),
mMode(aMode),
mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID),
mCurrentScrollbarTarget(FrameMetrics::NULL_SCROLL_ID),
mCurrentScrollbarFlags(0),
mPerspectiveItemIndex(0),
mSVGEffectsBuildingDepth(0),
mContainsBlendMode(false),
mIsBuildingScrollbar(false),
@@ -1837,17 +1838,22 @@ nsDisplayList::GetBounds(nsDisplayListBu
nsRect
nsDisplayList::GetClippedBoundsWithRespectToASR(nsDisplayListBuilder* aBuilder,
const ActiveScrolledRoot* aASR) const {
nsRect bounds;
for (nsDisplayItem* i = GetBottom(); i != nullptr; i = i->GetAbove()) {
nsRect r = i->GetClippedBounds(aBuilder);
if (aASR != i->GetActiveScrolledRoot() && !r.IsEmpty()) {
const DisplayItemClip* clip = DisplayItemClipChain::ClipForASR(i->GetClipChain(), aASR);
- MOZ_ASSERT(clip, "Need to be clipped wrt aASR. Do not call this function with an ASR that our child items don't have finite bounds wrt.");
+#ifdef DEBUG
+ if (!gfxPrefs::LayoutUseContainersForRootFrames()) {
+ MOZ_ASSERT(clip,
+ "Need to be clipped wrt aASR. Do not call this function with an ASR that our child items don't have finite bounds wrt.");
+ }
+#endif
if (clip) {
r = clip->GetClipRect();
}
}
bounds.UnionRect(bounds, r);
}
return bounds;
}
@@ -1863,17 +1869,21 @@ nsDisplayList::GetVisibleRect() const {
bool
nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion) {
PROFILER_LABEL("nsDisplayList", "ComputeVisibilityForRoot",
js::ProfileEntry::Category::GRAPHICS);
nsRegion r;
- r.And(*aVisibleRegion, GetClippedBoundsWithRespectToASR(aBuilder, nullptr));
+ const ActiveScrolledRoot* rootASR = nullptr;
+ if (gfxPrefs::LayoutUseContainersForRootFrames()) {
+ rootASR = aBuilder->ActiveScrolledRootForRootScrollframe();
+ }
+ r.And(*aVisibleRegion, GetClippedBoundsWithRespectToASR(aBuilder, rootASR));
return ComputeVisibilityForSublist(aBuilder, aVisibleRegion, r.GetBounds());
}
static nsRegion
TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
{
bool snap;
nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap);