--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -4852,18 +4852,18 @@ PresShell::ClipListToRange(nsDisplayList
nscoord x = std::min(startPoint.x, endPoint.x);
textRect.x += x;
textRect.width = std::max(startPoint.x, endPoint.x) - x;
}
surfaceRect.UnionRect(surfaceRect, textRect);
DisplayItemClip newClip;
newClip.SetTo(textRect);
- newClip.IntersectWith(i->GetClip());
- i->SetClip(aBuilder, newClip);
+ DisplayItemClipChain newClipChain = { newClip, i->GetActiveScrolledRoot(), nullptr };
+ i->IntersectClip(aBuilder, &newClipChain);
itemToInsert = i;
}
}
// Don't try to descend into subdocuments.
// If this ever changes we'd need to add handling for subdocuments with
// different zoom levels.
else if (content->GetUncomposedDoc() ==
aRange->GetStartParent()->GetUncomposedDoc()) {
--- a/layout/base/nsLayoutDebugger.cpp
+++ b/layout/base/nsLayoutDebugger.cpp
@@ -10,17 +10,16 @@
#include "nsILayoutDebugger.h"
#include "nsAttrValue.h"
#include "nsFrame.h"
#include "nsDisplayList.h"
#include "FrameLayerBuilder.h"
#include "nsPrintfCString.h"
-#include "DisplayItemScrollClip.h"
#include <iostream>
#include <stdio.h>
using namespace mozilla;
using namespace mozilla::layers;
#ifdef DEBUG
@@ -145,25 +144,26 @@ PrintDisplayItemTo(nsDisplayListBuilder*
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) scrollClip(%s)%s ref=0x%p agr=0x%p",
+ 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) asr(%s) clipChain(%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(),
- DisplayItemScrollClip::ToString(aItem->ScrollClip()).get(),
+ ActiveScrolledRoot::ToString(aItem->GetActiveScrolledRoot()).get(),
+ DisplayItemClipChain::ToString(aItem->GetClipChain()).get(),
aItem->IsUniform(aBuilder) ? " uniform" : "",
aItem->ReferenceFrame(), aItem->GetAnimatedGeometryRoot()->mFrame);
for (auto iter = opaque.RectIter(); !iter.Done(); iter.Next()) {
const nsRect& r = iter.Get();
aStream << nsPrintfCString(" (opaque %d,%d,%d,%d)", r.x, r.y, r.width, r.height);
}
--- a/layout/generic/ViewportFrame.cpp
+++ b/layout/generic/ViewportFrame.cpp
@@ -97,24 +97,27 @@ ShouldInTopLayerForFullscreen(Element* a
static void
BuildDisplayListForTopLayerFrame(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
nsDisplayList* aList)
{
nsRect dirty;
DisplayListClipState::AutoClipMultiple clipState(aBuilder);
+ nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
nsDisplayListBuilder::OutOfFlowDisplayData*
savedOutOfFlowData = nsDisplayListBuilder::GetOutOfFlowData(aFrame);
if (savedOutOfFlowData) {
dirty = savedOutOfFlowData->mDirtyRect;
- clipState.SetClipForContainingBlockDescendants(
- &savedOutOfFlowData->mContainingBlockClip);
- clipState.SetScrollClipForContainingBlockDescendants(
- savedOutOfFlowData->mContainingBlockScrollClip);
+ clipState.SetClipChainForContainingBlockDescendants(
+ savedOutOfFlowData->mContainingBlockClipChain);
+ clipState.ClipContainingBlockDescendantsExtra(
+ dirty + aBuilder->ToReferenceFrame(aFrame), nullptr);
+ asrSetter.SetCurrentActiveScrolledRoot(
+ savedOutOfFlowData->mContainingBlockActiveScrolledRoot);
}
nsDisplayList list;
aFrame->BuildDisplayListForStackingContext(aBuilder, dirty, &list);
aList->AppendToTop(&list);
}
void
ViewportFrame::BuildDisplayListForTopLayer(nsDisplayListBuilder* aBuilder,
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -472,60 +472,89 @@ nsCanvasFrame::BuildDisplayList(nsDispla
new (aBuilder) nsDisplayCanvasThemedBackground(aBuilder, this));
return;
}
if (!bg) {
return;
}
- const DisplayItemScrollClip* scrollClip =
- aBuilder->ClipState().GetCurrentInnermostScrollClip();
+ const ActiveScrolledRoot* asr =
+ aBuilder->CurrentActiveScrolledRoot();
bool needBlendContainer = false;
+ nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
// Create separate items for each background layer.
const nsStyleImageLayers& layers = bg->mImage;
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, layers) {
if (layers.mLayers[i].mImage.IsEmpty()) {
continue;
}
if (layers.mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) {
needBlendContainer = true;
}
nsRect bgRect = GetRectRelativeToSelf() + aBuilder->ToReferenceFrame(this);
+
+ const ActiveScrolledRoot* thisItemASR = asr;
+ nsDisplayList thisItemList;
nsDisplayBackgroundImage::InitData bgData =
nsDisplayBackgroundImage::GetInitData(aBuilder, this, i, bgRect, bg,
nsDisplayBackgroundImage::LayerizeFixed::ALWAYS_LAYERIZE_FIXED_BACKGROUND);
- nsDisplayList thisItemList;
if (bgData.shouldFixToViewport) {
- nsDisplayCanvasBackgroundImage* bgItem =
- new (aBuilder) nsDisplayCanvasBackgroundImage(bgData);
+
+ auto* displayData = aBuilder->GetCurrentFixedBackgroundDisplayData();
+ nsDisplayListBuilder::AutoBuildingDisplayList
+ buildingDisplayList(aBuilder, this, aBuilder->GetDirtyRect(), false);
+
+ DisplayListClipState::AutoSaveRestore clipState(aBuilder);
+ nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
+ if (displayData) {
+ nsRect dirtyRect = displayData->mDirtyRect + GetOffsetTo(PresContext()->GetPresShell()->GetRootFrame());
+ buildingDisplayList.SetDirtyRect(dirtyRect);
+ clipState.SetClipChainForContainingBlockDescendants(
+ displayData->mContainingBlockClipChain);
+ asrSetter.SetCurrentActiveScrolledRoot(
+ displayData->mContainingBlockActiveScrolledRoot);
+ thisItemASR = displayData->mContainingBlockActiveScrolledRoot;
+ }
+ nsDisplayCanvasBackgroundImage* bgItem = nullptr;
+ {
+ DisplayListClipState::AutoSaveRestore bgImageClip(aBuilder);
+ bgImageClip.Clear();
+ bgItem = new (aBuilder) nsDisplayCanvasBackgroundImage(bgData);
+ }
thisItemList.AppendNewToTop(
nsDisplayFixedPosition::CreateForFixedBackground(aBuilder, this, bgItem, i));
+
} else {
thisItemList.AppendNewToTop(new (aBuilder) nsDisplayCanvasBackgroundImage(bgData));
}
if (layers.mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) {
+ DisplayListClipState::AutoSaveRestore blendClip(aBuilder);
+ blendClip.ClearUpToASR(thisItemASR);
thisItemList.AppendNewToTop(
new (aBuilder) nsDisplayBlendMode(aBuilder, this, &thisItemList,
layers.mLayers[i].mBlendMode,
- scrollClip, i + 1));
+ thisItemASR, i + 1));
}
aLists.BorderBackground()->AppendToTop(&thisItemList);
}
if (needBlendContainer) {
+ const ActiveScrolledRoot* containerASR = contASRTracker.GetContainerASR();
+ DisplayListClipState::AutoSaveRestore blendContainerClip(aBuilder);
+ blendContainerClip.ClearUpToASR(containerASR);
aLists.BorderBackground()->AppendNewToTop(
nsDisplayBlendContainer::CreateForBackgroundBlendMode(aBuilder, this,
aLists.BorderBackground(),
- scrollClip));
+ containerASR));
}
}
for (nsIFrame* kid : PrincipalChildList()) {
// Put our child into its own pseudo-stack.
BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
}
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -80,17 +80,16 @@
#include "nsChangeHint.h"
#include "nsDeckFrame.h"
#include "nsSubDocumentFrame.h"
#include "SVGTextFrame.h"
#include "gfxContext.h"
#include "nsRenderingContext.h"
#include "nsAbsoluteContainingBlock.h"
-#include "DisplayItemScrollClip.h"
#include "StickyScrollContainer.h"
#include "nsFontInflationData.h"
#include "nsRegion.h"
#include "nsIFrameInlines.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/EffectCompositor.h"
#include "mozilla/EffectSet.h"
@@ -2271,85 +2270,81 @@ nsIFrame::BuildDisplayListForStackingCon
// multiple container display items and wrap them around our contents.
// This enum lists all the potential container display items, in the order
// outside to inside.
enum class ContainerItemType : uint8_t {
eNone = 0,
eOwnLayerIfNeeded,
eBlendMode,
eFixedPosition,
- eStickyPosition,
eOwnLayerForTransformWithRoundedClip,
ePerspective,
eTransform,
eSeparatorTransforms,
eOpacity,
eFilter,
eBlendContainer
};
+ nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
+
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
// If there is a current clip, then depending on the container items we
// create, different things can happen to it. Some container items simply
// propagate the clip to their children and aren't clipped themselves.
// But other container items, especially those that establish a different
// geometry for their contents (e.g. transforms), capture the clip on
// themselves and unset the clip for their contents. If we create more than
// one of those container items, the clip will be captured on the outermost
// one and the inner container items will be unclipped.
ContainerItemType clipCapturedBy = ContainerItemType::eNone;
if (useFixedPosition) {
clipCapturedBy = ContainerItemType::eFixedPosition;
- } else if (useStickyPosition) {
- clipCapturedBy = ContainerItemType::eStickyPosition;
} else if (isTransformed) {
- if ((hasPerspective || extend3DContext) && clipState.SavedStateHasRoundedCorners()) {
+ const DisplayItemClipChain* currentClip =
+ aBuilder->ClipState().GetCurrentCombinedClipChain(aBuilder);
+ if ((hasPerspective || extend3DContext) &&
+ (currentClip && currentClip->HasRoundedCorners())) {
// If we're creating an nsDisplayTransform item that is going to combine
// its transform with its children (preserve-3d or perspective), then we
// can't have an intermediate surface. Mask layers force an intermediate
// surface, so if we're going to need both then create a separate
// wrapping layer for the mask.
clipCapturedBy = ContainerItemType::eOwnLayerForTransformWithRoundedClip;
} else if (hasPerspective) {
clipCapturedBy = ContainerItemType::ePerspective;
} else {
clipCapturedBy = ContainerItemType::eTransform;
}
} else if (usingFilter) {
clipCapturedBy = ContainerItemType::eFilter;
}
- bool clearClip = false;
if (clipCapturedBy != ContainerItemType::eNone) {
- // We don't need to pass ancestor clipping down to our children;
- // everything goes inside a display item's child list, and the display
- // item itself will be clipped.
- // For transforms we also need to clear ancestor clipping because it's
- // relative to the wrong display item reference frame anyway.
- clearClip = true;
- }
-
- clipState.EnterStackingContextContents(clearClip);
+ clipState.Clear();
+ }
nsDisplayListCollection set;
{
DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
nsDisplayListBuilder::AutoInTransformSetter
inTransformSetter(aBuilder, inTransform);
nsDisplayListBuilder::AutoSaveRestorePerspectiveIndex
perspectiveIndex(aBuilder, this);
CheckForApzAwareEventHandlers(aBuilder, this);
- Maybe<nsRect> clipPropClip = GetClipPropClipRect(disp, effects, GetSize());
- if (clipPropClip) {
- dirtyRect.IntersectRect(dirtyRect, *clipPropClip);
- nestedClipState.ClipContentDescendants(
- *clipPropClip + aBuilder->ToReferenceFrame(this));
+ Maybe<nsRect> contentClip =
+ GetClipPropClipRect(disp, effects, GetSize());
+
+ if (contentClip) {
+ dirtyRect.IntersectRect(dirtyRect, *contentClip);
+ nestedClipState.ClipContentDescendants(*contentClip +
+ aBuilder->ToReferenceFrame(this));
}
// extend3DContext also guarantees that applyAbsPosClipping and usingSVGEffects are false
// We only modify the preserve-3d rect if we are the top of a preserve-3d heirarchy
if (extend3DContext) {
// Mark these first so MarkAbsoluteFramesForDisplayList knows if we are
// going to be forced to descend into frames.
aBuilder->MarkPreserve3DFramesForDisplayList(this);
@@ -2429,50 +2424,45 @@ nsIFrame::BuildDisplayListForStackingCon
}
#ifdef DEBUG
DisplayDebugBorders(aBuilder, this, set);
#endif
resultList.AppendToTop(set.Outlines());
// 8, 9: non-negative z-index children
resultList.AppendToTop(set.PositionedDescendants());
- // Get the scroll clip to use for the container items that we create here.
- // If we cleared the clip, and we create multiple container items, then the
- // items we create before we restore the clip will have a different scroll
- // clip from the items we create after we restore the clip.
- const DisplayItemScrollClip* containerItemScrollClip =
- aBuilder->ClipState().CurrentAncestorScrollClipForStackingContextContents();
+ // Get the ASR to use for the container items that we create here.
+ const ActiveScrolledRoot* containerItemASR = contASRTracker.GetContainerASR();
/* If adding both a nsDisplayBlendContainer and a nsDisplayBlendMode to the
* same list, the nsDisplayBlendContainer should be added first. This only
* happens when the element creating this stacking context has mix-blend-mode
* and also contains a child which has mix-blend-mode.
* The nsDisplayBlendContainer must be added to the list first, so it does not
* isolate the containing element blending as well.
*/
-
if (aBuilder->ContainsBlendMode()) {
DisplayListClipState::AutoSaveRestore blendContainerClipState(aBuilder);
- blendContainerClipState.Clear();
+ blendContainerClipState.ClearUpToASR(containerItemASR);
resultList.AppendNewToTop(
nsDisplayBlendContainer::CreateForMixBlendMode(aBuilder, this, &resultList,
- containerItemScrollClip));
+ containerItemASR));
}
/* If there are any SVG effects, wrap the list up in an SVG effects item
* (which also handles CSS group opacity). Note that we create an SVG effects
* item even if resultList is empty, since a filter can produce graphical
* output even if the element being filtered wouldn't otherwise do so.
*/
if (usingSVGEffects) {
MOZ_ASSERT(usingFilter ||usingMask,
"Beside filter & mask/clip-path, what else effect do we have?");
if (clipCapturedBy == ContainerItemType::eFilter) {
- clipState.ExitStackingContextContents(&containerItemScrollClip);
+ clipState.Restore();
}
// Revert to the post-filter dirty rect.
buildingDisplayList.SetDirtyRect(dirtyRectOutsideSVGEffects);
// Skip all filter effects while generating glyph mask.
if (usingFilter && !aBuilder->IsForGenerateGlyphMask()) {
// If we are going to create a mask display item, handle opacity effect
// in that mask display item; Otherwise, take care of opacity in this
@@ -2482,41 +2472,42 @@ nsIFrame::BuildDisplayListForStackingCon
/* List now emptied, so add the new list to the top. */
resultList.AppendNewToTop(
new (aBuilder) nsDisplayFilter(aBuilder, this, &resultList,
handleOpacity));
}
if (usingMask) {
DisplayListClipState::AutoSaveRestore maskClipState(aBuilder);
- maskClipState.Clear();
+ maskClipState.ClearUpToASR(containerItemASR);
/* List now emptied, so add the new list to the top. */
resultList.AppendNewToTop(
new (aBuilder) nsDisplayMask(aBuilder, this, &resultList,
- !useOpacity, containerItemScrollClip));
+ !useOpacity, containerItemASR));
}
// Also add the hoisted scroll info items. We need those for APZ scrolling
// because nsDisplayMask items can't build active layers.
aBuilder->ExitSVGEffectsContents();
resultList.AppendToTop(&hoistedScrollInfoItemsStorage);
}
/* If the list is non-empty and there is CSS group opacity without SVG
* effects, wrap it up in an opacity item.
*/
if (useOpacity && !resultList.IsEmpty()) {
// Don't clip nsDisplayOpacity items. We clip their descendants instead.
// The clip we would set on an element with opacity would clip
// all descendant content, but some should not be clipped.
DisplayListClipState::AutoSaveRestore opacityClipState(aBuilder);
- opacityClipState.Clear();
+ opacityClipState.ClearUpToASR(containerItemASR);
resultList.AppendNewToTop(
new (aBuilder) nsDisplayOpacity(aBuilder, this, &resultList,
- containerItemScrollClip, opacityItemForEventsAndPluginsOnly));
+ containerItemASR,
+ opacityItemForEventsAndPluginsOnly));
}
/* If we're going to apply a transformation and don't have preserve-3d set, wrap
* everything in an nsDisplayTransform. If there's nothing in the list, don't add
* anything.
*
* For the preserve-3d case we want to individually wrap every child in the list with
* a separate nsDisplayTransform instead. When the child is already an nsDisplayTransform,
@@ -2552,17 +2543,17 @@ nsIFrame::BuildDisplayListForStackingCon
WrapSeparatorTransform(aBuilder, this, dirtyRect,
&nonparticipants, &participants, index++);
resultList.AppendToTop(&participants);
}
if (isTransformed && !resultList.IsEmpty()) {
if (clipCapturedBy == ContainerItemType::eTransform) {
// Restore clip state now so nsDisplayTransform is clipped properly.
- clipState.ExitStackingContextContents(&containerItemScrollClip);
+ clipState.Restore();
}
// Revert to the dirtyrect coming in from the parent, without our transform
// taken into account.
buildingDisplayList.SetDirtyRect(dirtyRectOutsideTransform);
// Revert to the outer reference frame and offset because all display
// items we create from now on are outside the transform.
nsPoint toOuterReferenceFrame;
const nsIFrame* outerReferenceFrame = this;
@@ -2579,72 +2570,86 @@ nsIFrame::BuildDisplayListForStackingCon
new (aBuilder) nsDisplayTransform(aBuilder, this,
&resultList, dirtyRect, 0,
allowAsyncAnimation);
resultList.AppendNewToTop(transformItem);
}
if (hasPerspective) {
if (clipCapturedBy == ContainerItemType::ePerspective) {
- clipState.ExitStackingContextContents(&containerItemScrollClip);
+ clipState.Restore();
}
resultList.AppendNewToTop(
new (aBuilder) nsDisplayPerspective(
aBuilder, this,
GetContainingBlock()->GetContent()->GetPrimaryFrame(), &resultList));
}
}
if (clipCapturedBy == ContainerItemType::eOwnLayerForTransformWithRoundedClip) {
- clipState.ExitStackingContextContents(&containerItemScrollClip);
+ clipState.Restore();
resultList.AppendNewToTop(
- new (aBuilder) nsDisplayOwnLayer(aBuilder, this, &resultList, 0,
+ new (aBuilder) nsDisplayOwnLayer(aBuilder, this, &resultList,
+ aBuilder->CurrentActiveScrolledRoot(), 0,
mozilla::layers::FrameMetrics::NULL_SCROLL_ID,
0.0f, /* aForceActive = */ false));
}
/* If we have sticky positioning, wrap it in a sticky position item.
*/
if (useFixedPosition) {
if (clipCapturedBy == ContainerItemType::eFixedPosition) {
- clipState.ExitStackingContextContents(&containerItemScrollClip);
- }
+ clipState.Restore();
+ }
+ // The ASR for the fixed item should be the ASR of our containing block,
+ // which has been set as the builder's current ASR, unless this frame is
+ // invisible and we hadn't saved display item data for it. In that case,
+ // we need to take the containerItemASR since we might have fixed children.
+ const ActiveScrolledRoot* fixedASR =
+ ActiveScrolledRoot::PickAncestor(containerItemASR, aBuilder->CurrentActiveScrolledRoot());
resultList.AppendNewToTop(
- new (aBuilder) nsDisplayFixedPosition(aBuilder, this, &resultList));
+ new (aBuilder) nsDisplayFixedPosition(aBuilder, this, &resultList, fixedASR));
} else if (useStickyPosition) {
- if (clipCapturedBy == ContainerItemType::eStickyPosition) {
- clipState.ExitStackingContextContents(&containerItemScrollClip);
- }
+ // For position:sticky, the clip needs to be applied both to the sticky
+ // container item and to the contents. The container item needs the clip
+ // because a scrolled clip needs to move independently from the sticky
+ // contents, and the contents need the clip so that they have finite
+ // clipped bounds with respect to the container item's ASR. The latter is
+ // a little tricky in the case where the sticky item has both fixed and
+ // non-fixed descendants, because that means that the sticky container
+ // item's ASR is the ASR of the fixed descendant.
+ const ActiveScrolledRoot* stickyASR =
+ ActiveScrolledRoot::PickAncestor(containerItemASR, aBuilder->CurrentActiveScrolledRoot());
resultList.AppendNewToTop(
- new (aBuilder) nsDisplayStickyPosition(aBuilder, this, &resultList));
+ new (aBuilder) nsDisplayStickyPosition(aBuilder, this, &resultList, stickyASR));
}
/* If there's blending, wrap up the list in a blend-mode item. Note
* that opacity can be applied before blending as the blend color is
* not affected by foreground opacity (only background alpha).
*/
if (useBlendMode && !resultList.IsEmpty()) {
- DisplayListClipState::AutoSaveRestore mixBlendClipState(aBuilder);
- mixBlendClipState.Clear();
+ DisplayListClipState::AutoSaveRestore blendModeClipState(aBuilder);
+ blendModeClipState.ClearUpToASR(containerItemASR);
resultList.AppendNewToTop(
new (aBuilder) nsDisplayBlendMode(aBuilder, this, &resultList,
effects->mMixBlendMode,
- containerItemScrollClip));
+ containerItemASR));
}
CreateOwnLayerIfNeeded(aBuilder, &resultList);
aList->AppendToTop(&resultList);
}
static nsDisplayItem*
WrapInWrapList(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
- const DisplayItemScrollClip* aScrollClip)
+ const ActiveScrolledRoot* aContainerASR)
{
nsDisplayItem* item = aList->GetBottom();
if (!item) {
return nullptr;
}
// For perspective items we want to treat the 'frame' as being the transform
// frame that created it. This stops the transform frame from wrapping another
@@ -2652,17 +2657,17 @@ WrapInWrapList(nsDisplayListBuilder* aBu
// makes the perspective frame create one (so we have an atomic entry for z-index
// sorting).
nsIFrame *itemFrame = item->Frame();
if (item->GetType() == nsDisplayItem::TYPE_PERSPECTIVE) {
itemFrame = static_cast<nsDisplayPerspective*>(item)->TransformFrame();
}
if (item->GetAbove() || itemFrame != aFrame) {
- return new (aBuilder) nsDisplayWrapList(aBuilder, aFrame, aList, aScrollClip);
+ return new (aBuilder) nsDisplayWrapList(aBuilder, aFrame, aList, aContainerASR);
}
aList->RemoveBottom();
return item;
}
void
nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
nsIFrame* aChild,
@@ -2829,39 +2834,39 @@ nsIFrame::BuildDisplayListForChild(nsDis
pseudoStackingContext = true;
}
NS_ASSERTION(!isStackingContext || pseudoStackingContext,
"Stacking contexts must also be pseudo-stacking-contexts");
nsDisplayListBuilder::AutoBuildingDisplayList
buildingForChild(aBuilder, child, dirty, pseudoStackingContext);
DisplayListClipState::AutoClipMultiple clipState(aBuilder);
+ nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
CheckForApzAwareEventHandlers(aBuilder, child);
if (savedOutOfFlowData) {
aBuilder->SetBuildingInvisibleItems(false);
- clipState.SetClipForContainingBlockDescendants(
- &savedOutOfFlowData->mContainingBlockClip);
- clipState.SetScrollClipForContainingBlockDescendants(
- savedOutOfFlowData->mContainingBlockScrollClip);
+ clipState.SetClipChainForContainingBlockDescendants(
+ savedOutOfFlowData->mContainingBlockClipChain);
+ asrSetter.SetCurrentActiveScrolledRoot(
+ savedOutOfFlowData->mContainingBlockActiveScrolledRoot);
} else if (GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO &&
isPlaceholder) {
NS_ASSERTION(dirty.IsEmpty(), "should have empty dirty rect");
// Every item we build from now until we descent into an out of flow that
// does have saved out of flow data should be invisible. This state gets
// restored when AutoBuildingDisplayList gets out of scope.
aBuilder->SetBuildingInvisibleItems(true);
// If we have nested out-of-flow frames and the outer one isn't visible
// then we won't have stored clip data for it. We can just clear the clip
// instead since we know we won't render anything, and the inner out-of-flow
// frame will setup the correct clip for itself.
- clipState.SetClipForContainingBlockDescendants(nullptr);
- clipState.SetScrollClipForContainingBlockDescendants(nullptr);
+ clipState.SetClipChainForContainingBlockDescendants(nullptr);
}
// Setup clipping for the parent's overflow:-moz-hidden-unscrollable,
// or overflow:hidden on elements that don't support scrolling (and therefore
// don't create nsHTML/XULScrollFrame). This clipping needs to not clip
// anything directly rendered by the parent, only the rendering of its
// children.
// Don't use overflowClip to restrict the dirty rect, since some of the
@@ -2869,24 +2874,27 @@ nsIFrame::BuildDisplayListForChild(nsDis
// display items, they'll be pruned during ComputeVisibility.
nsIFrame* parent = child->GetParent();
const nsStyleDisplay* parentDisp =
parent == this ? ourDisp : parent->StyleDisplay();
ApplyOverflowClipping(aBuilder, parent, parentDisp, clipState);
nsDisplayList list;
nsDisplayList extraPositionedDescendants;
+ const ActiveScrolledRoot* wrapListASR = aBuilder->CurrentActiveScrolledRoot();
if (isStackingContext) {
if (effects->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
aBuilder->SetContainsBlendMode(true);
}
// True stacking context.
// For stacking contexts, BuildDisplayListForStackingContext handles
// clipping and MarkAbsoluteFramesForDisplayList.
+ nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
child->BuildDisplayListForStackingContext(aBuilder, dirty, &list);
+ wrapListASR = contASRTracker.GetContainerASR();
aBuilder->DisplayCaret(child, dirty, &list);
} else {
Maybe<nsRect> clipPropClip =
child->GetClipPropClipRect(disp, effects, child->GetSize());
if (clipPropClip) {
dirty.IntersectRect(dirty, *clipPropClip);
clipState.ClipContentDescendants(
*clipPropClip + aBuilder->ToReferenceFrame(child));
@@ -2933,54 +2941,53 @@ nsIFrame::BuildDisplayListForChild(nsDis
}
// A pseudo-stacking context (e.g., a positioned element with z-index auto).
// We allow positioned descendants of the child to escape to our parent
// stacking context's positioned descendant list, because they might be
// z-index:non-auto
nsDisplayListCollection pseudoStack;
aBuilder->AdjustWindowDraggingRegion(child);
+ nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
child->BuildDisplayList(aBuilder, dirty, pseudoStack);
aBuilder->DisplayCaret(child, dirty, pseudoStack.Content());
+ wrapListASR = contASRTracker.GetContainerASR();
list.AppendToTop(pseudoStack.BorderBackground());
list.AppendToTop(pseudoStack.BlockBorderBackgrounds());
list.AppendToTop(pseudoStack.Floats());
list.AppendToTop(pseudoStack.Content());
list.AppendToTop(pseudoStack.Outlines());
extraPositionedDescendants.AppendToTop(pseudoStack.PositionedDescendants());
#ifdef DEBUG
DisplayDebugBorders(aBuilder, child, aLists);
#endif
}
buildingForChild.RestoreBuildingInvisibleItemsValue();
// Clear clip rect for the construction of the items below. Since we're
// clipping all their contents, they themselves don't need to be clipped.
- clipState.Clear();
-
- const DisplayItemScrollClip* containerItemScrollClip =
- aBuilder->ClipState().CurrentAncestorScrollClipForStackingContextContents();
+ clipState.ClearUpToASR(wrapListASR);
if (isPositioned || isVisuallyAtomic ||
(aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
// Genuine stacking contexts, and positioned pseudo-stacking-contexts,
// go in this level.
if (!list.IsEmpty()) {
- nsDisplayItem* item = WrapInWrapList(aBuilder, child, &list, containerItemScrollClip);
+ nsDisplayItem* item = WrapInWrapList(aBuilder, child, &list, wrapListASR);
if (isSVG) {
aLists.Content()->AppendNewToTop(item);
} else {
aLists.PositionedDescendants()->AppendNewToTop(item);
}
}
} else if (!isSVG && disp->IsFloating(child)) {
if (!list.IsEmpty()) {
- aLists.Floats()->AppendNewToTop(WrapInWrapList(aBuilder, child, &list, containerItemScrollClip));
+ aLists.Floats()->AppendNewToTop(WrapInWrapList(aBuilder, child, &list, wrapListASR));
}
} else {
aLists.Content()->AppendToTop(&list);
}
// We delay placing the positioned descendants of positioned frames to here,
// because in the absence of z-index this is the correct order for them.
// This doesn't affect correctness because the positioned descendants list
// is sorted by z-order and content in BuildDisplayListForStackingContext,
@@ -10051,17 +10058,17 @@ nsIFrame::SetParent(nsContainerFrame* aP
void
nsIFrame::CreateOwnLayerIfNeeded(nsDisplayListBuilder* aBuilder,
nsDisplayList* aList)
{
if (GetContent() &&
GetContent()->IsXULElement() &&
GetContent()->HasAttr(kNameSpaceID_None, nsGkAtoms::layer)) {
aList->AppendNewToTop(new (aBuilder)
- nsDisplayOwnLayer(aBuilder, this, aList));
+ nsDisplayOwnLayer(aBuilder, this, aList, aBuilder->CurrentActiveScrolledRoot()));
}
}
bool
nsIFrame::IsSelected() const
{
return (GetContent() && GetContent()->IsSelectionDescendant()) ?
IsFrameSelected() : false;
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -5,17 +5,16 @@
/* rendering object to wrap rendering objects that should be scrollable */
#include "nsGfxScrollFrame.h"
#include "ActiveLayerTracker.h"
#include "base/compiler_specific.h"
#include "DisplayItemClip.h"
-#include "DisplayItemScrollClip.h"
#include "nsCOMPtr.h"
#include "nsIContentViewer.h"
#include "nsPresContext.h"
#include "nsView.h"
#include "nsIScrollable.h"
#include "nsContainerFrame.h"
#include "nsGkAtoms.h"
#include "nsNameSpaceManager.h"
@@ -2980,23 +2979,24 @@ static const uint32_t APPEND_SCROLLBAR_C
static void
AppendToTop(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists,
nsDisplayList* aSource, nsIFrame* aSourceFrame, uint32_t aFlags)
{
if (aSource->IsEmpty())
return;
nsDisplayWrapList* newItem;
+ const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
if (aFlags & APPEND_OWN_LAYER) {
uint32_t flags = (aFlags & APPEND_SCROLLBAR_CONTAINER)
? nsDisplayOwnLayer::SCROLLBAR_CONTAINER
: 0;
- newItem = new (aBuilder) nsDisplayOwnLayer(aBuilder, aSourceFrame, aSource, flags);
+ newItem = new (aBuilder) nsDisplayOwnLayer(aBuilder, aSourceFrame, aSource, asr, flags);
} else {
- newItem = new (aBuilder) nsDisplayWrapList(aBuilder, aSourceFrame, aSource);
+ newItem = new (aBuilder) nsDisplayWrapList(aBuilder, aSourceFrame, aSource, asr);
}
if (aFlags & APPEND_POSITIONED) {
// We want overlay scrollbars to always be on top of the scrolled content,
// but we don't want them to unnecessarily cover overlapping elements from
// outside our scroll frame.
int32_t zIndex = MaxZIndexInList(aLists.PositionedDescendants(), aBuilder);
AppendInternalItemToTop(aLists, newItem, zIndex);
@@ -3178,69 +3178,54 @@ ShouldBeClippedByFrame(nsIFrame* aClipFr
{
return nsLayoutUtils::IsProperAncestorFrame(aClipFrame, aClippedFrame);
}
static void
ClipItemsExceptCaret(nsDisplayList* aList,
nsDisplayListBuilder* aBuilder,
nsIFrame* aClipFrame,
- const DisplayItemClip* aNonCaretClip,
- const DisplayItemScrollClip* aNonCaretScrollClip)
+ const DisplayItemClipChain* aExtraClip,
+ nsDataHashtable<nsPtrHashKey<const DisplayItemClipChain>, const DisplayItemClipChain*>& aCache)
{
for (nsDisplayItem* i = aList->GetBottom(); i; i = i->GetAbove()) {
if (!ShouldBeClippedByFrame(aClipFrame, i->Frame())) {
continue;
}
if (i->GetType() != nsDisplayItem::TYPE_CARET) {
- bool unused;
- nsRect bounds = i->GetBounds(aBuilder, &unused);
- if (aNonCaretClip && aNonCaretClip->IsRectAffectedByClip(bounds)) {
- DisplayItemClip newClip;
- newClip.IntersectWith(i->GetClip());
- newClip.IntersectWith(*aNonCaretClip);
- i->SetClip(aBuilder, newClip);
- }
-
- if (aNonCaretScrollClip) {
- const DisplayItemScrollClip* currentScrollClip = i->ScrollClip();
- MOZ_ASSERT(DisplayItemScrollClip::IsAncestor(aNonCaretScrollClip->mParent,
- currentScrollClip));
-
- // Overwrite the existing scroll clip with aNonCaretScrollClip, unless
- // the current scroll clip is deeper than aNonCaretScrollClip (which
- // means that the display item is nested inside another scroll frame).
- if (!currentScrollClip ||
- currentScrollClip->mParent == aNonCaretScrollClip->mParent) {
- i->SetScrollClip(aNonCaretScrollClip);
- }
+ const DisplayItemClipChain* clip = i->GetClipChain();
+ const DisplayItemClipChain* intersection = nullptr;
+ if (aCache.Get(clip, &intersection)) {
+ i->SetClipChain(intersection);
+ } else {
+ i->IntersectClip(aBuilder, aExtraClip);
+ aCache.Put(clip, i->GetClipChain());
}
}
nsDisplayList* children = i->GetSameCoordinateSystemChildren();
if (children) {
- ClipItemsExceptCaret(children, aBuilder, aClipFrame, aNonCaretClip,
- aNonCaretScrollClip);
+ ClipItemsExceptCaret(children, aBuilder, aClipFrame, aExtraClip, aCache);
}
}
}
static void
ClipListsExceptCaret(nsDisplayListCollection* aLists,
nsDisplayListBuilder* aBuilder,
nsIFrame* aClipFrame,
- const DisplayItemClip* aNonCaretClip,
- const DisplayItemScrollClip* aNonCaretScrollClip)
-{
- ClipItemsExceptCaret(aLists->BorderBackground(), aBuilder, aClipFrame, aNonCaretClip, aNonCaretScrollClip);
- ClipItemsExceptCaret(aLists->BlockBorderBackgrounds(), aBuilder, aClipFrame, aNonCaretClip, aNonCaretScrollClip);
- ClipItemsExceptCaret(aLists->Floats(), aBuilder, aClipFrame, aNonCaretClip, aNonCaretScrollClip);
- ClipItemsExceptCaret(aLists->PositionedDescendants(), aBuilder, aClipFrame, aNonCaretClip, aNonCaretScrollClip);
- ClipItemsExceptCaret(aLists->Outlines(), aBuilder, aClipFrame, aNonCaretClip, aNonCaretScrollClip);
- ClipItemsExceptCaret(aLists->Content(), aBuilder, aClipFrame, aNonCaretClip, aNonCaretScrollClip);
+ const DisplayItemClipChain* aExtraClip)
+{
+ nsDataHashtable<nsPtrHashKey<const DisplayItemClipChain>, const DisplayItemClipChain*> cache;
+ ClipItemsExceptCaret(aLists->BorderBackground(), aBuilder, aClipFrame, aExtraClip, cache);
+ ClipItemsExceptCaret(aLists->BlockBorderBackgrounds(), aBuilder, aClipFrame, aExtraClip, cache);
+ ClipItemsExceptCaret(aLists->Floats(), aBuilder, aClipFrame, aExtraClip, cache);
+ ClipItemsExceptCaret(aLists->PositionedDescendants(), aBuilder, aClipFrame, aExtraClip, cache);
+ ClipItemsExceptCaret(aLists->Outlines(), aBuilder, aClipFrame, aExtraClip, cache);
+ ClipItemsExceptCaret(aLists->Content(), aBuilder, aClipFrame, aExtraClip, cache);
}
void
ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists)
{
if (aBuilder->IsForFrameVisibility()) {
@@ -3375,37 +3360,44 @@ ScrollFrameHelper::BuildDisplayList(nsDi
const nsStyleDisplay* disp = mOuter->StyleDisplay();
if (disp && (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_SCROLL)) {
aBuilder->AddToWillChangeBudget(mOuter, GetScrollPositionClampingScrollPortSize());
}
mScrollParentID = aBuilder->GetCurrentScrollParentId();
- Maybe<nsRect> contentBoxClipForCaret;
- Maybe<nsRect> contentBoxClipForNonCaretContent;
+ Maybe<nsRect> contentBoxClip;
+ Maybe<DisplayItemClipChain> extraContentBoxClipForNonCaretContent;
if (MOZ_UNLIKELY(mOuter->StyleDisplay()->mOverflowClipBox ==
NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX)) {
// We only clip if there is *scrollable* overflow, to avoid clipping
// *visual* overflow unnecessarily.
nsRect clipRect = mScrollPort + aBuilder->ToReferenceFrame(mOuter);
nsRect so = mScrolledFrame->GetScrollableOverflowRect();
if (clipRect.width != so.width || clipRect.height != so.height ||
so.x < 0 || so.y < 0) {
clipRect.Deflate(mOuter->GetUsedPadding());
- contentBoxClipForNonCaretContent = Some(clipRect);
- if (nsIFrame* caretFrame = aBuilder->GetCaretFrame()) {
- // Avoid clipping it in a zero-height line box (heuristic only).
- if (caretFrame->GetRect().height != 0) {
- nsRect caretRect = aBuilder->GetCaretRect();
- // Allow the caret to stick out of the content box clip by half the
- // caret height on the top, and its full width on the right.
- clipRect.Inflate(nsMargin(caretRect.height / 2, caretRect.width, 0, 0));
- contentBoxClipForCaret = Some(clipRect);
- }
+
+ // The non-inflated clip needs to be set on all non-caret items.
+ // We prepare an extra DisplayItemClipChain here that will be intersected
+ // with those items after they've been created.
+ const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
+ extraContentBoxClipForNonCaretContent = Some(DisplayItemClipChain{ DisplayItemClip(), asr, nullptr });
+ extraContentBoxClipForNonCaretContent->mClip.SetTo(clipRect);
+
+ nsIFrame* caretFrame = aBuilder->GetCaretFrame();
+ // Avoid clipping it in a zero-height line box (heuristic only).
+ if (caretFrame && caretFrame->GetRect().height != 0) {
+ nsRect caretRect = aBuilder->GetCaretRect();
+ // Allow the caret to stick out of the content box clip by half the
+ // 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;
@@ -3437,45 +3429,32 @@ ScrollFrameHelper::BuildDisplayList(nsDi
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
if (mClipAllDescendants) {
clipState.ClipContentDescendants(clipRect, haveRadii ? radii : nullptr);
} else {
clipState.ClipContainingBlockDescendants(clipRect, haveRadii ? radii : nullptr);
}
- DisplayItemScrollClip* inactiveScrollClip = nullptr;
+ Maybe<DisplayListClipState::AutoSaveRestore> contentBoxClipState;;
+ if (contentBoxClip) {
+ contentBoxClipState.emplace(aBuilder);
+ if (mClipAllDescendants) {
+ contentBoxClipState->ClipContentDescendants(*contentBoxClip);
+ } else {
+ contentBoxClipState->ClipContainingBlockDescendants(*contentBoxClip);
+ }
+ }
+
+ nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
+ if (mWillBuildScrollableLayer) {
+ asrSetter.EnterScrollFrame(sf);
+ }
{
- DisplayListClipState::AutoSaveRestore contentBoxClipState(aBuilder);
- if (contentBoxClipForCaret) {
- if (mClipAllDescendants) {
- contentBoxClipState.ClipContentDescendants(*contentBoxClipForCaret);
- } else {
- contentBoxClipState.ClipContainingBlockDescendants(*contentBoxClipForCaret);
- }
- }
-
- DisplayListClipState::AutoSaveRestore clipStateForScrollClip(aBuilder);
- if (mWillBuildScrollableLayer) {
- if (mClipAllDescendants) {
- clipStateForScrollClip.TurnClipIntoScrollClipForContentDescendants(aBuilder, sf);
- } else {
- clipStateForScrollClip.TurnClipIntoScrollClipForContainingBlockDescendants(aBuilder, sf);
- }
- } else {
- // Create a scroll clip anyway because we might need to activate for scroll handoff.
- if (mClipAllDescendants) {
- inactiveScrollClip = clipStateForScrollClip.InsertInactiveScrollClipForContentDescendants(aBuilder, sf);
- } else {
- inactiveScrollClip = clipStateForScrollClip.InsertInactiveScrollClipForContainingBlockDescendants(aBuilder, sf);
- }
- MOZ_ASSERT(!inactiveScrollClip->mIsAsyncScrollable);
- }
-
// 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();
if (usingDisplayPort) {
@@ -3498,67 +3477,54 @@ ScrollFrameHelper::BuildDisplayList(nsDi
scrolledRectClip = scrolledRectClip.Intersect(dirtyRect);
}
scrolledRectClipState.ClipContainingBlockDescendants(
scrolledRectClip + aBuilder->ToReferenceFrame(mOuter));
mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, dirtyRect, scrolledContent);
}
- if (contentBoxClipForNonCaretContent) {
- DisplayListClipState::AutoSaveRestore contentBoxClipState(aBuilder);
- if (mClipAllDescendants) {
- contentBoxClipState.ClipContentDescendants(*contentBoxClipForNonCaretContent);
- } else {
- contentBoxClipState.ClipContainingBlockDescendants(*contentBoxClipForNonCaretContent);
- }
-
- DisplayListClipState::AutoSaveRestore clipStateForScrollClip(aBuilder);
- if (mWillBuildScrollableLayer) {
- if (mClipAllDescendants) {
- clipStateForScrollClip.TurnClipIntoScrollClipForContentDescendants(aBuilder, sf);
- } else {
- clipStateForScrollClip.TurnClipIntoScrollClipForContainingBlockDescendants(aBuilder, sf);
- }
- }
- const DisplayItemClip* clipNonCaret = aBuilder->ClipState().GetCurrentCombinedClip(aBuilder);
- const DisplayItemScrollClip* scrollClipNonCaret = aBuilder->ClipState().GetCurrentInnermostScrollClip();
+ if (extraContentBoxClipForNonCaretContent) {
+ // The items were built while the inflated content box clip was in
+ // effect, so that the caret wasn't clipped unnecessarily. We apply
+ // the non-inflated clip to the non-caret items now, by intersecting
+ // it with their existing clip.
ClipListsExceptCaret(&scrolledContent, aBuilder, mScrolledFrame,
- clipNonCaret, scrollClipNonCaret);
+ extraContentBoxClipForNonCaretContent.ptr());
}
if (aBuilder->IsPaintingToWindow()) {
mIsScrollParent = idSetter.ShouldForceLayerForScrollParent();
}
if (idSetter.ShouldForceLayerForScrollParent() &&
!gfxPrefs::LayoutUseContainersForRootFrames())
{
// Note that forcing layerization of scroll parents follows the scroll
// handoff chain which is subject to the out-of-flow-frames caveat noted
// above (where the idSetter variable is created).
//
// This is not compatible when using containes for root scrollframes.
MOZ_ASSERT(couldBuildLayer && mScrolledFrame->GetContent());
- if (inactiveScrollClip) {
- inactiveScrollClip->mIsAsyncScrollable = true;
- }
if (!mWillBuildScrollableLayer) {
// Set a displayport so next paint we don't have to force layerization
// after the fact.
nsLayoutUtils::SetDisplayPortMargins(mOuter->GetContent(),
mOuter->PresContext()->PresShell(),
ScreenMargin(),
0,
nsLayoutUtils::RepaintMode::DoNotRepaint);
// Call DecideScrollableLayer to recompute mWillBuildScrollableLayer and
// recompute the current animated geometry root if needed.
// It's too late to change the dirty rect so pass a copy.
nsRect copyOfDirtyRect = dirtyRect;
Unused << DecideScrollableLayer(aBuilder, ©OfDirtyRect,
/* aAllowCreateDisplayPort = */ false);
+ if (mWillBuildScrollableLayer) {
+ asrSetter.InsertScrollFrame(sf);
+ }
}
}
}
if (mWillBuildScrollableLayer) {
aBuilder->ForceLayerForScrollParent();
}
--- a/layout/generic/nsPluginFrame.cpp
+++ b/layout/generic/nsPluginFrame.cpp
@@ -49,17 +49,16 @@
#include "ImageLayers.h"
#include "nsPluginInstanceOwner.h"
#ifdef XP_WIN
#include "gfxWindowsNativeDrawing.h"
#include "gfxWindowsSurface.h"
#endif
-#include "DisplayItemScrollClip.h"
#include "Layers.h"
#include "ReadbackLayer.h"
#include "ImageContainer.h"
// accessibility support
#ifdef ACCESSIBILITY
#include "nsAccessibilityService.h"
#endif
@@ -1005,20 +1004,18 @@ nsDisplayPlugin::Paint(nsDisplayListBuil
f->PaintPlugin(aBuilder, *aCtx, mVisibleRect, GetBounds(aBuilder, &snap));
}
static nsRect
GetClippedBoundsIncludingAllScrollClips(nsDisplayItem* aItem,
nsDisplayListBuilder* aBuilder)
{
nsRect r = aItem->GetClippedBounds(aBuilder);
- for (auto* sc = aItem->ScrollClip(); sc; sc = sc->mParent) {
- if (sc->mClip) {
- r = sc->mClip->ApplyNonRoundedIntersection(r);
- }
+ for (auto* sc = aItem->GetClipChain(); sc; sc = sc->mParent) {
+ r = sc->mClip.ApplyNonRoundedIntersection(r);
}
return r;
}
bool
nsDisplayPlugin::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion)
{
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -316,17 +316,17 @@ WrapBackgroundColorInOwnLayer(nsDisplayL
nsDisplayList* aList)
{
nsDisplayList tempItems;
nsDisplayItem* item;
while ((item = aList->RemoveBottom()) != nullptr) {
if (item->GetType() == nsDisplayItem::TYPE_BACKGROUND_COLOR) {
nsDisplayList tmpList;
tmpList.AppendToTop(item);
- item = new (aBuilder) nsDisplayOwnLayer(aBuilder, aFrame, &tmpList);
+ item = new (aBuilder) nsDisplayOwnLayer(aBuilder, aFrame, &tmpList, aBuilder->CurrentActiveScrolledRoot());
}
tempItems.AppendToTop(item);
}
aList->AppendToTop(&tempItems);
}
void
nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
@@ -451,17 +451,17 @@ nsSubDocumentFrame::BuildDisplayList(nsD
{
DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
if (needsOwnLayer) {
// Clear current clip. There's no point in propagating it down, since
// the layer we will construct will be clipped by the current clip.
// In fact for nsDisplayZoom propagating it down would be incorrect since
// nsDisplayZoom changes the meaning of appunits.
- nestedClipState.EnterStackingContextContents(true);
+ nestedClipState.Clear();
}
if (subdocRootFrame) {
nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(
aBuilder,
ignoreViewportScrolling && rootScrollFrame && rootScrollFrame->GetContent()
? nsLayoutUtils::FindOrCreateIDFor(rootScrollFrame->GetContent())
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -4821,23 +4821,21 @@ public:
return false;
}
return true;
}
void ApplyOpacity(nsDisplayListBuilder* aBuilder,
float aOpacity,
- const DisplayItemClip* aClip) override
+ const DisplayItemClipChain* aClip) override
{
NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
mOpacity = aOpacity;
- if (aClip) {
- IntersectClip(aBuilder, *aClip);
- }
+ IntersectClip(aBuilder, aClip);
}
void WriteDebugInfo(std::stringstream& aStream) override
{
#ifdef DEBUG
aStream << " (\"";
nsTextFrame* f = static_cast<nsTextFrame*>(mFrame);
@@ -4855,19 +4853,17 @@ public:
void GetMergedFrames(nsTArray<nsIFrame*>* aFrames) override
{
aFrames->AppendElements(mMergedFrames);
}
bool TryMerge(nsDisplayItem* aItem) override {
if (aItem->GetType() != TYPE_TEXT)
return false;
- if (aItem->GetClip() != GetClip())
- return false;
- if (aItem->ScrollClip() != ScrollClip())
+ if (aItem->GetClipChain() != GetClipChain())
return false;
nsDisplayText* other = static_cast<nsDisplayText*>(aItem);
if (!mFont || !other->mFont || mFont != other->mFont) {
return false;
}
if (mOpacity != other->mOpacity) {
return false;
--- a/layout/painting/DisplayListClipState.cpp
+++ b/layout/painting/DisplayListClipState.cpp
@@ -1,204 +1,171 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DisplayListClipState.h"
-#include "DisplayItemScrollClip.h"
#include "nsDisplayList.h"
namespace mozilla {
-const DisplayItemClip*
-DisplayListClipState::GetCurrentCombinedClip(nsDisplayListBuilder* aBuilder)
+void
+DisplayListClipState::ClearUpToASR(const ActiveScrolledRoot* aASR)
{
- if (mCurrentCombinedClip) {
- return mCurrentCombinedClip;
+ while (mClipChainContentDescendants &&
+ ActiveScrolledRoot::IsAncestor(aASR, mClipChainContentDescendants->mASR)) {
+ mClipChainContentDescendants = mClipChainContentDescendants->mParent;
+ }
+ while (mClipChainContainingBlockDescendants &&
+ ActiveScrolledRoot::IsAncestor(aASR, mClipChainContainingBlockDescendants->mASR)) {
+ mClipChainContainingBlockDescendants = mClipChainContainingBlockDescendants->mParent;
}
- if (!mClipContentDescendants && !mClipContainingBlockDescendants) {
+ InvalidateCurrentCombinedClipChain(aASR);
+}
+
+const DisplayItemClipChain*
+DisplayListClipState::GetCurrentCombinedClipChain(nsDisplayListBuilder* aBuilder)
+{
+ if (mCurrentCombinedClipChainIsValid) {
+ return mCurrentCombinedClipChain;
+ }
+ if (!mClipChainContentDescendants && !mClipChainContainingBlockDescendants) {
+ mCurrentCombinedClipChain = nullptr;
+ mCurrentCombinedClipChainIsValid = true;
return nullptr;
}
- if (mClipContentDescendants) {
- if (mClipContainingBlockDescendants) {
- DisplayItemClip intersection = *mClipContentDescendants;
- intersection.IntersectWith(*mClipContainingBlockDescendants);
- mCurrentCombinedClip = aBuilder->AllocateDisplayItemClip(intersection);
- } else {
- mCurrentCombinedClip =
- aBuilder->AllocateDisplayItemClip(*mClipContentDescendants);
+
+ mCurrentCombinedClipChain =
+ aBuilder->CreateClipChainIntersection(mCurrentCombinedClipChain,
+ mClipChainContentDescendants,
+ mClipChainContainingBlockDescendants);
+ mCurrentCombinedClipChainIsValid = true;
+ return mCurrentCombinedClipChain;
+}
+
+static void
+ApplyClip(nsDisplayListBuilder* aBuilder,
+ const DisplayItemClipChain*& aClipToModify,
+ const ActiveScrolledRoot* aASR,
+ DisplayItemClipChain& aClipChainOnStack)
+{
+ aClipChainOnStack.mASR = aASR;
+ if (aClipToModify && aClipToModify->mASR == aASR) {
+ // Intersect with aClipToModify and replace the clip chain item.
+ aClipChainOnStack.mClip.IntersectWith(aClipToModify->mClip);
+ aClipChainOnStack.mParent = aClipToModify->mParent;
+ aClipToModify = &aClipChainOnStack;
+ } else if (!aClipToModify ||
+ ActiveScrolledRoot::IsAncestor(aClipToModify->mASR, aASR)) {
+ // Add a new clip chain item at the bottom.
+ aClipChainOnStack.mParent = aClipToModify;
+ aClipToModify = &aClipChainOnStack;
+ } else {
+ // We need to insert / intersect a DisplayItemClipChain in the middle of the
+ // aClipToModify chain. This is a very rare case.
+ // Find the common ancestor and have the builder create the DisplayItemClipChain
+ // intersection. This will create new DisplayItemClipChain objects for all
+ // descendants of ancestorSC and we will not hold on to a pointer to
+ // aClipChainOnStack.
+ const DisplayItemClipChain* ancestorSC = aClipToModify;
+ while (ancestorSC && ActiveScrolledRoot::IsAncestor(aASR, ancestorSC->mASR)) {
+ ancestorSC = ancestorSC->mParent;
}
- } else {
- mCurrentCombinedClip =
- aBuilder->AllocateDisplayItemClip(*mClipContainingBlockDescendants);
+ aClipChainOnStack.mParent = nullptr;
+ aClipToModify =
+ aBuilder->CreateClipChainIntersection(ancestorSC, aClipToModify, &aClipChainOnStack);
}
- return mCurrentCombinedClip;
}
void
-DisplayListClipState::ClipContainingBlockDescendants(const nsRect& aRect,
+DisplayListClipState::ClipContainingBlockDescendants(nsDisplayListBuilder* aBuilder,
+ const nsRect& aRect,
const nscoord* aRadii,
- DisplayItemClip& aClipOnStack)
+ DisplayItemClipChain& aClipChainOnStack)
{
if (aRadii) {
- aClipOnStack.SetTo(aRect, aRadii);
+ aClipChainOnStack.mClip.SetTo(aRect, aRadii);
} else {
- aClipOnStack.SetTo(aRect);
+ aClipChainOnStack.mClip.SetTo(aRect);
}
- if (mClipContainingBlockDescendants) {
- aClipOnStack.IntersectWith(*mClipContainingBlockDescendants);
- }
- mClipContainingBlockDescendants = &aClipOnStack;
- mCurrentCombinedClip = nullptr;
+ const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
+ ApplyClip(aBuilder, mClipChainContainingBlockDescendants, asr, aClipChainOnStack);
+ InvalidateCurrentCombinedClipChain(asr);
}
void
-DisplayListClipState::ClipContentDescendants(const nsRect& aRect,
+DisplayListClipState::ClipContentDescendants(nsDisplayListBuilder* aBuilder,
+ const nsRect& aRect,
const nscoord* aRadii,
- DisplayItemClip& aClipOnStack)
+ DisplayItemClipChain& aClipChainOnStack)
{
if (aRadii) {
- aClipOnStack.SetTo(aRect, aRadii);
+ aClipChainOnStack.mClip.SetTo(aRect, aRadii);
} else {
- aClipOnStack.SetTo(aRect);
+ aClipChainOnStack.mClip.SetTo(aRect);
}
- if (mClipContentDescendants) {
- aClipOnStack.IntersectWith(*mClipContentDescendants);
- }
- mClipContentDescendants = &aClipOnStack;
- mCurrentCombinedClip = nullptr;
+ const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
+ ApplyClip(aBuilder, mClipChainContentDescendants, asr, aClipChainOnStack);
+ InvalidateCurrentCombinedClipChain(asr);
}
void
-DisplayListClipState::ClipContentDescendants(const nsRect& aRect,
+DisplayListClipState::ClipContentDescendants(nsDisplayListBuilder* aBuilder,
+ const nsRect& aRect,
const nsRect& aRoundedRect,
const nscoord* aRadii,
- DisplayItemClip& aClipOnStack)
+ DisplayItemClipChain& aClipChainOnStack)
{
if (aRadii) {
- aClipOnStack.SetTo(aRect, aRoundedRect, aRadii);
+ aClipChainOnStack.mClip.SetTo(aRect, aRoundedRect, aRadii);
} else {
nsRect intersect = aRect.Intersect(aRoundedRect);
- aClipOnStack.SetTo(intersect);
+ aClipChainOnStack.mClip.SetTo(intersect);
}
- if (mClipContentDescendants) {
- aClipOnStack.IntersectWith(*mClipContentDescendants);
+ const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
+ ApplyClip(aBuilder, mClipChainContentDescendants, asr, aClipChainOnStack);
+ InvalidateCurrentCombinedClipChain(asr);
+}
+
+
+void
+DisplayListClipState::InvalidateCurrentCombinedClipChain(const ActiveScrolledRoot* aInvalidateUpTo)
+{
+ mCurrentCombinedClipChainIsValid = false;
+ while (mCurrentCombinedClipChain &&
+ ActiveScrolledRoot::IsAncestor(aInvalidateUpTo, mCurrentCombinedClipChain->mASR)) {
+ mCurrentCombinedClipChain = mCurrentCombinedClipChain->mParent;
}
- mClipContentDescendants = &aClipOnStack;
- mCurrentCombinedClip = nullptr;
}
void
DisplayListClipState::ClipContainingBlockDescendantsToContentBox(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
- DisplayItemClip& aClipOnStack,
+ DisplayItemClipChain& aClipChainOnStack,
uint32_t aFlags)
{
nscoord radii[8];
bool hasBorderRadius = aFrame->GetContentBoxBorderRadii(radii);
if (!hasBorderRadius && (aFlags & ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT)) {
return;
}
nsRect clipRect = aFrame->GetContentRectRelativeToSelf() +
aBuilder->ToReferenceFrame(aFrame);
// If we have a border-radius, we have to clip our content to that
// radius.
- ClipContainingBlockDescendants(clipRect, hasBorderRadius ? radii : nullptr,
- aClipOnStack);
-}
-
-const DisplayItemScrollClip*
-DisplayListClipState::GetCurrentInnermostScrollClip()
-{
- return DisplayItemScrollClip::PickDescendant(
- mScrollClipContentDescendants, mScrollClipContainingBlockDescendants);
-}
-
-void
-DisplayListClipState::TurnClipIntoScrollClipForContentDescendants(
- nsDisplayListBuilder* aBuilder, nsIScrollableFrame* aScrollableFrame)
-{
- const DisplayItemScrollClip* parent = GetCurrentInnermostScrollClip();
- mScrollClipContentDescendants =
- aBuilder->AllocateDisplayItemScrollClip(parent,
- aScrollableFrame,
- GetCurrentCombinedClip(aBuilder), true);
- Clear();
-}
-
-void
-DisplayListClipState::TurnClipIntoScrollClipForContainingBlockDescendants(
- nsDisplayListBuilder* aBuilder, nsIScrollableFrame* aScrollableFrame)
-{
- const DisplayItemScrollClip* parent = GetCurrentInnermostScrollClip();
- mScrollClipContainingBlockDescendants =
- aBuilder->AllocateDisplayItemScrollClip(parent,
- aScrollableFrame,
- GetCurrentCombinedClip(aBuilder), true);
- Clear();
-}
-
-const DisplayItemClip*
-WithoutRoundedCorners(nsDisplayListBuilder* aBuilder, const DisplayItemClip* aClip)
-{
- if (!aClip) {
- return nullptr;
- }
- DisplayItemClip rectClip(*aClip);
- rectClip.RemoveRoundedCorners();
- return aBuilder->AllocateDisplayItemClip(rectClip);
-}
-
-DisplayItemScrollClip*
-DisplayListClipState::CreateInactiveScrollClip(
- nsDisplayListBuilder* aBuilder, nsIScrollableFrame* aScrollableFrame)
-{
- // We ignore the rounded corners on the current clip because we don't want
- // them to be double-applied (as scroll clip and as regular clip).
- // Double-applying rectangle clips doesn't make a visual difference so it's
- // fine.
- const DisplayItemClip* rectClip =
- WithoutRoundedCorners(aBuilder, GetCurrentCombinedClip(aBuilder));
-
- const DisplayItemScrollClip* parent = GetCurrentInnermostScrollClip();
- DisplayItemScrollClip* scrollClip =
- aBuilder->AllocateDisplayItemScrollClip(parent,
- aScrollableFrame,
- rectClip, false);
- return scrollClip;
-}
-
-DisplayItemScrollClip*
-DisplayListClipState::InsertInactiveScrollClipForContentDescendants(
- nsDisplayListBuilder* aBuilder, nsIScrollableFrame* aScrollableFrame)
-{
- DisplayItemScrollClip* scrollClip =
- CreateInactiveScrollClip(aBuilder, aScrollableFrame);
- mScrollClipContentDescendants = scrollClip;
- return scrollClip;
-}
-
-DisplayItemScrollClip*
-DisplayListClipState::InsertInactiveScrollClipForContainingBlockDescendants(
- nsDisplayListBuilder* aBuilder, nsIScrollableFrame* aScrollableFrame)
-{
- DisplayItemScrollClip* scrollClip =
- CreateInactiveScrollClip(aBuilder, aScrollableFrame);
- mScrollClipContainingBlockDescendants = scrollClip;
- return scrollClip;
+ ClipContainingBlockDescendants(aBuilder, clipRect, hasBorderRadius ? radii : nullptr,
+ aClipChainOnStack);
}
DisplayListClipState::AutoSaveRestore::AutoSaveRestore(nsDisplayListBuilder* aBuilder)
- : mState(aBuilder->ClipState())
+ : mBuilder(aBuilder)
+ , mState(aBuilder->ClipState())
, mSavedState(aBuilder->ClipState())
#ifdef DEBUG
, mClipUsed(false)
, mRestored(false)
#endif
- , mClearedForStackingContextContents(false)
-{
- mState.mStackingContextAncestorSC = mState.GetCurrentInnermostScrollClip();
-}
+{}
} // namespace mozilla
--- a/layout/painting/DisplayListClipState.h
+++ b/layout/painting/DisplayListClipState.h
@@ -3,218 +3,160 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DISPLAYLISTCLIPSTATE_H_
#define DISPLAYLISTCLIPSTATE_H_
#include "DisplayItemClip.h"
#include "DisplayItemClipChain.h"
-#include "DisplayItemScrollClip.h"
#include "mozilla/DebugOnly.h"
class nsIFrame;
class nsIScrollableFrame;
class nsDisplayListBuilder;
namespace mozilla {
/**
* All clip coordinates are in appunits relative to the reference frame
* for the display item we're building.
*/
class DisplayListClipState {
public:
DisplayListClipState()
- : mClipContentDescendants(nullptr)
- , mClipContainingBlockDescendants(nullptr)
- , mCurrentCombinedClip(nullptr)
- , mScrollClipContentDescendants(nullptr)
- , mScrollClipContainingBlockDescendants(nullptr)
- , mStackingContextAncestorSC(nullptr)
+ : mClipChainContentDescendants(nullptr)
+ , mClipChainContainingBlockDescendants(nullptr)
+ , mCurrentCombinedClipChain(nullptr)
+ , mCurrentCombinedClipChainIsValid(false)
{}
/**
- * Returns intersection of mClipContainingBlockDescendants and
- * mClipContentDescendants, allocated on aBuilder's arena.
+ * Returns intersection of mClipChainContainingBlockDescendants and
+ * mClipChainContentDescendants, allocated on aBuilder's arena.
*/
- const DisplayItemClip* GetCurrentCombinedClip(nsDisplayListBuilder* aBuilder);
+ const DisplayItemClipChain* GetCurrentCombinedClipChain(nsDisplayListBuilder* aBuilder);
- const DisplayItemClip* GetClipForContainingBlockDescendants() const
+ const DisplayItemClipChain* GetClipChainForContainingBlockDescendants() const
{
- return mClipContainingBlockDescendants;
+ return mClipChainContainingBlockDescendants;
}
- const DisplayItemClip* GetClipForContentDescendants() const
+ const DisplayItemClipChain* GetClipChainForContentDescendants() const
{
- return mClipContentDescendants;
+ return mClipChainContentDescendants;
}
- const DisplayItemScrollClip* GetCurrentInnermostScrollClip();
-
- const DisplayItemScrollClip* CurrentAncestorScrollClipForStackingContextContents()
+ const ActiveScrolledRoot* GetContentClipASR() const
{
- return mStackingContextAncestorSC;
+ return mClipChainContentDescendants ? mClipChainContentDescendants->mASR : nullptr;
}
class AutoSaveRestore;
friend class AutoSaveRestore;
class AutoClipContainingBlockDescendantsToContentBox;
friend class AutoClipContainingBlockDescendantsToContentBox;
class AutoClipMultiple;
friend class AutoClipMultiple;
enum {
ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT = 0x01
};
private:
- void SetClipForContainingBlockDescendants(const DisplayItemClip* aClip)
- {
- mClipContainingBlockDescendants = aClip;
- mCurrentCombinedClip = nullptr;
- }
-
- void SetScrollClipForContainingBlockDescendants(const DisplayItemScrollClip* aScrollClip)
- {
- mScrollClipContainingBlockDescendants = aScrollClip;
- mStackingContextAncestorSC = DisplayItemScrollClip::PickAncestor(mStackingContextAncestorSC, aScrollClip);
- }
void Clear()
{
- mClipContentDescendants = nullptr;
- mClipContainingBlockDescendants = nullptr;
- mCurrentCombinedClip = nullptr;
- // We do not clear scroll clips.
- }
-
- void EnterStackingContextContents(bool aClear)
- {
- if (aClear) {
- mClipContentDescendants = nullptr;
- mClipContainingBlockDescendants = nullptr;
- mCurrentCombinedClip = nullptr;
- mScrollClipContentDescendants = nullptr;
- mScrollClipContainingBlockDescendants = nullptr;
- mStackingContextAncestorSC = nullptr;
- } else {
- mStackingContextAncestorSC = GetCurrentInnermostScrollClip();
- }
+ mClipChainContentDescendants = nullptr;
+ mClipChainContainingBlockDescendants = nullptr;
+ mCurrentCombinedClipChain = nullptr;
+ mCurrentCombinedClipChainIsValid = false;
}
- /**
- * Clear the current clip, and instead add it as a scroll clip to the current
- * scroll clip chain.
- */
- void TurnClipIntoScrollClipForContentDescendants(nsDisplayListBuilder* aBuilder,
- nsIScrollableFrame* aScrollableFrame);
- void TurnClipIntoScrollClipForContainingBlockDescendants(nsDisplayListBuilder* aBuilder,
- nsIScrollableFrame* aScrollableFrame);
+ void ClearUpToASR(const ActiveScrolledRoot* aASR);
- /**
- * Insert a scroll clip without clearing the current clip.
- * The returned DisplayItemScrollClip will have mIsAsyncScrollable == false,
- * and it can be activated once the scroll frame knows that it needs to be
- * async scrollable.
- */
- DisplayItemScrollClip* InsertInactiveScrollClipForContentDescendants(nsDisplayListBuilder* aBuilder,
- nsIScrollableFrame* aScrollableFrame);
- DisplayItemScrollClip* InsertInactiveScrollClipForContainingBlockDescendants(nsDisplayListBuilder* aBuilder,
- nsIScrollableFrame* aScrollableFrame);
-
- DisplayItemScrollClip* CreateInactiveScrollClip(nsDisplayListBuilder* aBuilder,
- nsIScrollableFrame* aScrollableFrame);
+ void SetClipChainForContainingBlockDescendants(const DisplayItemClipChain* aClipChain)
+ {
+ mClipChainContainingBlockDescendants = aClipChain;
+ InvalidateCurrentCombinedClipChain(aClipChain ? aClipChain->mASR : nullptr);
+ }
/**
* Intersects the given clip rect (with optional aRadii) with the current
* mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to
* the result, stored in aClipOnStack.
*/
- void ClipContainingBlockDescendants(const nsRect& aRect,
+ void ClipContainingBlockDescendants(nsDisplayListBuilder* aBuilder,
+ const nsRect& aRect,
const nscoord* aRadii,
- DisplayItemClip& aClipOnStack);
+ DisplayItemClipChain& aClipChainOnStack);
- void ClipContentDescendants(const nsRect& aRect,
+ void ClipContentDescendants(nsDisplayListBuilder* aBuilder,
+ const nsRect& aRect,
const nscoord* aRadii,
- DisplayItemClip& aClipOnStack);
- void ClipContentDescendants(const nsRect& aRect,
+ DisplayItemClipChain& aClipChainOnStack);
+ void ClipContentDescendants(nsDisplayListBuilder* aBuilder,
+ const nsRect& aRect,
const nsRect& aRoundedRect,
const nscoord* aRadii,
- DisplayItemClip& aClipOnStack);
+ DisplayItemClipChain& aClipChainOnStack);
+
+ void InvalidateCurrentCombinedClipChain(const ActiveScrolledRoot* aInvalidateUpTo);
/**
* Clips containing-block descendants to the frame's content-box,
* taking border-radius into account.
* If aFlags contains ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT then
* we assume display items will not draw outside the content rect, so
* clipping is only required if there is a border-radius. This is an
* optimization to reduce the amount of clipping required.
*/
void ClipContainingBlockDescendantsToContentBox(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
- DisplayItemClip& aClipOnStack,
+ DisplayItemClipChain& aClipChainOnStack,
uint32_t aFlags);
/**
* All content descendants (i.e. following placeholder frames to their
- * out-of-flows if necessary) should be clipped by mClipContentDescendants.
+ * out-of-flows if necessary) should be clipped by mClipChainContentDescendants.
* Null if no clipping applies.
*/
- const DisplayItemClip* mClipContentDescendants;
+ const DisplayItemClipChain* mClipChainContentDescendants;
/**
* All containing-block descendants (i.e. frame descendants), including
* display items for the current frame, should be clipped by
- * mClipContainingBlockDescendants.
+ * mClipChainContainingBlockDescendants.
* Null if no clipping applies.
*/
- const DisplayItemClip* mClipContainingBlockDescendants;
+ const DisplayItemClipChain* mClipChainContainingBlockDescendants;
/**
- * The intersection of mClipContentDescendants and
- * mClipContainingBlockDescendants.
+ * The intersection of mClipChainContentDescendants and
+ * mClipChainContainingBlockDescendants.
* Allocated in the nsDisplayListBuilder arena. Null if none has been
- * allocated or both mClipContentDescendants and mClipContainingBlockDescendants
+ * allocated or both mClipChainContentDescendants and mClipChainContainingBlockDescendants
* are null.
*/
- const DisplayItemClip* mCurrentCombinedClip;
-
- /**
- * The same for scroll clips.
- */
- const DisplayItemScrollClip* mScrollClipContentDescendants;
- const DisplayItemScrollClip* mScrollClipContainingBlockDescendants;
-
- /**
- * A scroll clip that is an ancestor of all the scroll clips that were
- * "current" on this clip state since EnterStackingContextContents was
- * called.
- */
- const DisplayItemScrollClip* mStackingContextAncestorSC;
+ const DisplayItemClipChain* mCurrentCombinedClipChain;
+ bool mCurrentCombinedClipChainIsValid;
};
/**
* A class to automatically save and restore the current clip state. Also
* offers methods for modifying the clip state. Only one modification is allowed
* to be in scope at a time using one of these objects; multiple modifications
* require nested objects. The interface is written this way to prevent
* dangling pointers to DisplayItemClips.
*/
class DisplayListClipState::AutoSaveRestore {
public:
explicit AutoSaveRestore(nsDisplayListBuilder* aBuilder);
void Restore()
{
- if (!mClearedForStackingContextContents) {
- // Forward along the ancestor scroll clip to the original clip state.
- mSavedState.mStackingContextAncestorSC =
- DisplayItemScrollClip::PickAncestor(mSavedState.mStackingContextAncestorSC,
- mState.mStackingContextAncestorSC);
- }
mState = mSavedState;
#ifdef DEBUG
mRestored = true;
#endif
}
~AutoSaveRestore()
{
Restore();
@@ -224,150 +166,67 @@ public:
{
NS_ASSERTION(!mRestored, "Already restored!");
mState.Clear();
#ifdef DEBUG
mClipUsed = false;
#endif
}
- void EnterStackingContextContents(bool aClear)
+ void ClearUpToASR(const ActiveScrolledRoot* aASR)
{
NS_ASSERTION(!mRestored, "Already restored!");
- mState.EnterStackingContextContents(aClear);
- mClearedForStackingContextContents = aClear;
- }
-
- void ExitStackingContextContents(const DisplayItemScrollClip** aOutContainerSC)
- {
- if (mClearedForStackingContextContents) {
- // If we cleared the scroll clip, then the scroll clip that was current
- // just before we cleared it is the one that needs to be set on the
- // container item.
- *aOutContainerSC = mSavedState.GetCurrentInnermostScrollClip();
- } else {
- // If we didn't clear the scroll clip, then the container item needs to
- // get a scroll clip that's an ancestor of all its direct child items'
- // scroll clips.
- // The simplest way to satisfy this requirement would be to just take the
- // root scroll clip (i.e. nullptr). However, this can cause the bounds of
- // the container items to be enlarged unnecessarily, so instead we try to
- // take the "deepest" scroll clip that satisfies the requirement.
- // Usually this is the scroll clip that was current before we entered
- // the stacking context contents (call that the "initial scroll clip").
- // There are two cases in which the container scroll clip *won't* be the
- // initial scroll clip (instead the container scroll clip will be a
- // proper ancestor of the initial scroll clip):
- // (1) If SetScrollClipForContainingBlockDescendants was called with an
- // ancestor scroll clip of the initial scroll clip while we were
- // building our direct child items. This happens if we entered a
- // position:absolute or position:fixed element whose containing
- // block is an ancestor of the frame that generated the initial
- // scroll clip. Then the "ancestor scroll clip for stacking context
- // contents" will be set to that scroll clip.
- // (2) If one of our direct child items is a container item for which
- // (1) or (2) happened.
- *aOutContainerSC = mState.CurrentAncestorScrollClipForStackingContextContents();
- }
- Restore();
- }
-
- bool SavedStateHasRoundedCorners()
- {
- const DisplayItemScrollClip* scrollClip = mSavedState.GetCurrentInnermostScrollClip();
- if (scrollClip && scrollClip->HasRoundedCorners()) {
- return true;
- }
- const DisplayItemClip* clip = mSavedState.GetClipForContainingBlockDescendants();
- if (clip && clip->GetRoundedRectCount() > 0) {
- return true;
- }
-
- clip = mSavedState.GetClipForContentDescendants();
- if (clip && clip->GetRoundedRectCount() > 0) {
- return true;
- }
- return false;
- }
-
- void TurnClipIntoScrollClipForContentDescendants(nsDisplayListBuilder* aBuilder, nsIScrollableFrame* aScrollableFrame)
- {
- NS_ASSERTION(!mRestored, "Already restored!");
- mState.TurnClipIntoScrollClipForContentDescendants(aBuilder, aScrollableFrame);
+ mState.ClearUpToASR(aASR);
#ifdef DEBUG
- mClipUsed = true;
+ mClipUsed = false;
#endif
}
- void TurnClipIntoScrollClipForContainingBlockDescendants(nsDisplayListBuilder* aBuilder, nsIScrollableFrame* aScrollableFrame)
- {
- NS_ASSERTION(!mRestored, "Already restored!");
- mState.TurnClipIntoScrollClipForContainingBlockDescendants(aBuilder, aScrollableFrame);
-#ifdef DEBUG
- mClipUsed = true;
-#endif
- }
-
- DisplayItemScrollClip* InsertInactiveScrollClipForContentDescendants(nsDisplayListBuilder* aBuilder, nsIScrollableFrame* aScrollableFrame)
+ void SetClipChainForContainingBlockDescendants(const DisplayItemClipChain* aClipChain)
{
- NS_ASSERTION(!mRestored, "Already restored!");
- DisplayItemScrollClip* scrollClip = mState.InsertInactiveScrollClipForContentDescendants(aBuilder, aScrollableFrame);
-#ifdef DEBUG
- mClipUsed = true;
-#endif
- return scrollClip;
- }
-
- DisplayItemScrollClip* InsertInactiveScrollClipForContainingBlockDescendants(nsDisplayListBuilder* aBuilder, nsIScrollableFrame* aScrollableFrame)
- {
- NS_ASSERTION(!mRestored, "Already restored!");
- DisplayItemScrollClip* scrollClip = mState.InsertInactiveScrollClipForContainingBlockDescendants(aBuilder, aScrollableFrame);
-#ifdef DEBUG
- mClipUsed = true;
-#endif
- return scrollClip;
+ mState.SetClipChainForContainingBlockDescendants(aClipChain);
}
/**
* Intersects the given clip rect (with optional aRadii) with the current
* mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to
* the result, stored in aClipOnStack.
*/
void ClipContainingBlockDescendants(const nsRect& aRect,
const nscoord* aRadii = nullptr)
{
NS_ASSERTION(!mRestored, "Already restored!");
NS_ASSERTION(!mClipUsed, "mClip already used");
#ifdef DEBUG
mClipUsed = true;
#endif
- mState.ClipContainingBlockDescendants(aRect, aRadii, mClip);
+ mState.ClipContainingBlockDescendants(mBuilder, aRect, aRadii, mClipChain);
}
void ClipContentDescendants(const nsRect& aRect,
const nscoord* aRadii = nullptr)
{
NS_ASSERTION(!mRestored, "Already restored!");
NS_ASSERTION(!mClipUsed, "mClip already used");
#ifdef DEBUG
mClipUsed = true;
#endif
- mState.ClipContentDescendants(aRect, aRadii, mClip);
+ mState.ClipContentDescendants(mBuilder, aRect, aRadii, mClipChain);
}
void ClipContentDescendants(const nsRect& aRect,
const nsRect& aRoundedRect,
const nscoord* aRadii = nullptr)
{
NS_ASSERTION(!mRestored, "Already restored!");
NS_ASSERTION(!mClipUsed, "mClip already used");
#ifdef DEBUG
mClipUsed = true;
#endif
- mState.ClipContentDescendants(aRect, aRoundedRect, aRadii, mClip);
+ mState.ClipContentDescendants(mBuilder, aRect, aRoundedRect, aRadii, mClipChain);
}
/**
* Clips containing-block descendants to the frame's content-box,
* taking border-radius into account.
* If aFlags contains ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT then
* we assume display items will not draw outside the content rect, so
* clipping is only required if there is a border-radius. This is an
@@ -377,41 +236,41 @@ public:
nsIFrame* aFrame,
uint32_t aFlags = 0)
{
NS_ASSERTION(!mRestored, "Already restored!");
NS_ASSERTION(!mClipUsed, "mClip already used");
#ifdef DEBUG
mClipUsed = true;
#endif
- mState.ClipContainingBlockDescendantsToContentBox(aBuilder, aFrame, mClip, aFlags);
+ mState.ClipContainingBlockDescendantsToContentBox(aBuilder, aFrame, mClipChain, aFlags);
}
protected:
+ nsDisplayListBuilder* mBuilder;
DisplayListClipState& mState;
DisplayListClipState mSavedState;
- DisplayItemClip mClip;
+ DisplayItemClipChain mClipChain;
#ifdef DEBUG
bool mClipUsed;
bool mRestored;
#endif
- bool mClearedForStackingContextContents;
};
class DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox : public AutoSaveRestore {
public:
AutoClipContainingBlockDescendantsToContentBox(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
uint32_t aFlags = 0)
: AutoSaveRestore(aBuilder)
{
#ifdef DEBUG
mClipUsed = true;
#endif
- mState.ClipContainingBlockDescendantsToContentBox(aBuilder, aFrame, mClip, aFlags);
+ mState.ClipContainingBlockDescendantsToContentBox(aBuilder, aFrame, mClipChain, aFlags);
}
};
/**
* Do not use this outside of nsFrame::BuildDisplayListForChild, use
* multiple AutoSaveRestores instead. We provide this class just to ensure
* BuildDisplayListForChild is as efficient as possible.
*/
@@ -420,46 +279,33 @@ public:
explicit AutoClipMultiple(nsDisplayListBuilder* aBuilder)
: AutoSaveRestore(aBuilder)
#ifdef DEBUG
, mExtraClipUsed(false)
#endif
{}
/**
- * *aClip must survive longer than this object. Be careful!!!
- */
- void SetClipForContainingBlockDescendants(const DisplayItemClip* aClip)
- {
- mState.SetClipForContainingBlockDescendants(aClip);
- }
-
- void SetScrollClipForContainingBlockDescendants(const DisplayItemScrollClip* aScrollClip)
- {
- mState.SetScrollClipForContainingBlockDescendants(aScrollClip);
- }
-
- /**
* Intersects the given clip rect (with optional aRadii) with the current
* mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to
* the result, stored in aClipOnStack.
*/
void ClipContainingBlockDescendantsExtra(const nsRect& aRect,
const nscoord* aRadii)
{
NS_ASSERTION(!mRestored, "Already restored!");
NS_ASSERTION(!mExtraClipUsed, "mExtraClip already used");
#ifdef DEBUG
mExtraClipUsed = true;
#endif
- mState.ClipContainingBlockDescendants(aRect, aRadii, mExtraClip);
+ mState.ClipContainingBlockDescendants(mBuilder, aRect, aRadii, mExtraClipChain);
}
protected:
- DisplayItemClip mExtraClip;
+ DisplayItemClipChain mExtraClipChain;
#ifdef DEBUG
bool mExtraClipUsed;
#endif
};
} // namespace mozilla
#endif /* DISPLAYLISTCLIPSTATE_H_ */
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -8,17 +8,16 @@
#include "FrameLayerBuilder.h"
#include "mozilla/LookAndFeel.h"
#include "mozilla/Maybe.h"
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
#include "mozilla/gfx/Matrix.h"
#include "ActiveLayerTracker.h"
#include "BasicLayers.h"
-#include "DisplayItemScrollClip.h"
#include "ImageContainer.h"
#include "ImageLayers.h"
#include "LayerTreeInvalidation.h"
#include "Layers.h"
#include "LayerUserData.h"
#include "MaskLayerImageCache.h"
#include "UnitTransforms.h"
#include "Units.h"
@@ -418,23 +417,22 @@ struct AssignedDisplayItem
* PaintedLayer 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 PaintedLayerData {
public:
PaintedLayerData() :
mAnimatedGeometryRoot(nullptr),
- mScrollClip(nullptr),
+ mASR(nullptr),
mReferenceFrame(nullptr),
mLayer(nullptr),
mSolidColor(NS_RGBA(0, 0, 0, 0)),
mIsSolidColorInVisibleRegion(false),
mFontSmoothingBackgroundColor(NS_RGBA(0,0,0,0)),
- mSingleItemFixedToViewport(false),
mNeedComponentAlpha(false),
mForceTransparentSurface(false),
mHideAllLayersBelow(false),
mOpaqueForAnimatedGeometryRootParent(false),
mDisableFlattening(false),
mBackfaceHidden(false),
mImage(nullptr),
mCommonClipCount(-1),
@@ -553,20 +551,21 @@ public:
nsIntRect mScaledHitRegionBounds;
nsIntRect mScaledMaybeHitRegionBounds;
/**
* The "active scrolled root" for all content in the layer. Must
* be non-null; all content in a PaintedLayer must have the same
* active scrolled root.
*/
AnimatedGeometryRoot* mAnimatedGeometryRoot;
+ const ActiveScrolledRoot* mASR;
/**
- * The scroll clip for this layer.
+ * The chain of clips that should apply to this layer.
*/
- const DisplayItemScrollClip* mScrollClip;
+ const DisplayItemClipChain* mClipChain;
/**
* The offset between mAnimatedGeometryRoot and the reference frame.
*/
nsPoint mAnimatedGeometryRootOffset;
/**
* 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.
@@ -583,21 +582,16 @@ public:
*/
bool mIsSolidColorInVisibleRegion;
/**
* The target background color for smoothing fonts that are drawn on top of
* transparent parts of the layer.
*/
nscolor mFontSmoothingBackgroundColor;
/**
- * True if the layer contains exactly one item that returned true for
- * ShouldFixToViewport.
- */
- bool mSingleItemFixedToViewport;
- /**
* True if there is any text visible in the layer that's over
* transparent pixels in the layer.
*/
bool mNeedComponentAlpha;
/**
* Set if the layer should be treated as transparent, even if its entire
* area is covered by opaque display items. For example, this needs to
* be set if something is going to "punch holes" in the layer by clearing
@@ -673,29 +667,34 @@ public:
*/
nsTArray<AssignedDisplayItem> mAssignedDisplayItems;
};
struct NewLayerEntry {
NewLayerEntry()
: mAnimatedGeometryRoot(nullptr)
- , mScrollClip(nullptr)
+ , mASR(nullptr)
+ , mClipChain(nullptr)
+ , mScrollMetadataASR(nullptr)
, mLayerContentsVisibleRect(0, 0, -1, -1)
, mLayerState(LAYER_INACTIVE)
, mHideAllLayersBelow(false)
, mOpaqueForAnimatedGeometryRootParent(false)
, mPropagateComponentAlphaFlattening(true)
, mUntransformedVisibleRegion(false)
+ , mIsFixedToRootScrollFrame(false)
{}
// mLayer is null if the previous entry is for a PaintedLayer that hasn't
// been optimized to some other form (yet).
RefPtr<Layer> mLayer;
AnimatedGeometryRoot* mAnimatedGeometryRoot;
- const DisplayItemScrollClip* mScrollClip;
+ const ActiveScrolledRoot* mASR;
+ const DisplayItemClipChain* mClipChain;
+ const ActiveScrolledRoot* mScrollMetadataASR;
// If non-null, this ScrollMetadata is set to the be the first ScrollMetadata
// on the layer.
UniquePtr<ScrollMetadata> mBaseScrollMetadata;
// The following are only used for retained layers (for occlusion
// culling of those layers). These regions are all relative to the
// container reference frame.
nsIntRegion mVisibleRegion;
nsIntRegion mOpaqueRegion;
@@ -715,16 +714,17 @@ struct NewLayerEntry {
bool mOpaqueForAnimatedGeometryRootParent;
// If true, then the content flags for this layer should contribute
// to our decision to flatten component alpha layers, false otherwise.
bool mPropagateComponentAlphaFlattening;
// mVisibleRegion is relative to the associated frame before
// transform.
bool mUntransformedVisibleRegion;
+ bool mIsFixedToRootScrollFrame;
};
class PaintedLayerDataTree;
/**
* This is tree node type for PaintedLayerDataTree.
* Each node corresponds to a different animated geometry root, and contains
* a stack of PaintedLayerDatas, in bottom-to-top order.
@@ -770,17 +770,18 @@ public:
/**
* Find a PaintedLayerData in our mPaintedLayerDataStack that aItem can be
* added to. Creates a new PaintedLayerData by calling
* aNewPaintedLayerCallback if necessary.
*/
template<typename NewPaintedLayerCallbackType>
PaintedLayerData* FindPaintedLayerFor(const nsIntRect& aVisibleRect,
bool aBackfaceHidden,
- const DisplayItemScrollClip* aScrollClip,
+ const ActiveScrolledRoot* aASR,
+ const DisplayItemClipChain* aClipChain,
NewPaintedLayerCallbackType aNewPaintedLayerCallback);
/**
* Find an opaque background color for aRegion. Pulls a color from the parent
* geometry root if appropriate, but only if that color is present underneath
* the whole clip of this node, so that this node's contents can animate or
* move (possibly async) without having to change the background color.
* @param aUnderIndex Searching will start in mPaintedLayerDataStack right
@@ -944,17 +945,18 @@ public:
/**
* Find a PaintedLayerData for aItem. This can either be an existing
* PaintedLayerData from inside a node in our tree, or a new one that gets
* created by a call out to aNewPaintedLayerCallback.
*/
template<typename NewPaintedLayerCallbackType>
PaintedLayerData* FindPaintedLayerFor(AnimatedGeometryRoot* aAnimatedGeometryRoot,
- const DisplayItemScrollClip* aScrollClip,
+ const ActiveScrolledRoot* aASR,
+ const DisplayItemClipChain* aClipChain,
const nsIntRect& aVisibleRect,
bool aBackfaceidden,
NewPaintedLayerCallbackType aNewPaintedLayerCallback);
/**
* Finish everything.
*/
void Finish();
@@ -1043,24 +1045,27 @@ public:
FrameLayerBuilder* aLayerBuilder,
nsIFrame* aContainerFrame,
nsDisplayItem* aContainerItem,
const nsRect& aContainerBounds,
ContainerLayer* aContainerLayer,
const ContainerLayerParameters& aParameters,
bool aFlattenToSingleLayer,
nscolor aBackgroundColor,
- const DisplayItemScrollClip* aContainerScrollClip) :
+ const ActiveScrolledRoot* aContainerASR,
+ const ActiveScrolledRoot* aContainerScrollMetadataASR,
+ const ActiveScrolledRoot* aContainerCompositorASR) :
mBuilder(aBuilder), mManager(aManager),
mLayerBuilder(aLayerBuilder),
mContainerFrame(aContainerFrame),
mContainerLayer(aContainerLayer),
mContainerBounds(aContainerBounds),
- mContainerScrollClip(aContainerScrollClip),
- mScrollClipForPerspectiveChild(aParameters.mScrollClipForPerspectiveChild),
+ mContainerASR(aContainerASR),
+ mContainerScrollMetadataASR(aContainerScrollMetadataASR),
+ mContainerCompositorASR(aContainerCompositorASR),
mParameters(aParameters),
mPaintedLayerDataTree(*this, aBackgroundColor),
mFlattenToSingleLayer(aFlattenToSingleLayer)
{
nsPresContext* presContext = aContainerFrame->PresContext();
mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
mContainerReferenceFrame =
const_cast<nsIFrame*>(aContainerItem ? aContainerItem->ReferenceFrameForChildren() :
@@ -1284,17 +1289,17 @@ protected:
PaintedLayer* aNewLayer);
/**
* Returns true if aItem's opaque area (in aOpaque) covers the entire
* scrollable area of its presshell.
*/
bool ItemCoversScrollableArea(nsDisplayItem* aItem, const nsRegion& aOpaque);
/**
- * Set FrameMetrics and scroll-induced clipping on aEntry's layer.
+ * Set ScrollMetadata and scroll-induced clipping on aEntry's layer.
*/
void SetupScrollingMetadata(NewLayerEntry* aEntry);
/**
* Applies occlusion culling.
* For each layer in mNewChildLayers, remove from its visible region the
* opaque regions of the layers at higher z-index, but only if they have
* the same animated geometry root and fixed-pos frame ancestor.
@@ -1320,29 +1325,31 @@ protected:
bool* aOpaqueForAnimatedGeometryRootParent);
/**
* Return a PaintedLayerData object that is initialized for a layer that
* aItem will be assigned to.
* @param aItem The item that is going to be added.
* @param aVisibleRect The visible rect of the item.
* @param aAnimatedGeometryRoot The item's animated geometry root.
- * @param aScrollClip The scroll clip for this PaintedLayer.
+ * @param aASR The active scrolled root that moves this PaintedLayer.
+ * @param aClipChain The clip chain that the compositor needs to
+ * apply to this layer.
+ * @param aScrollMetadataASR The leaf ASR for which scroll metadata needs to be
+ * set on the layer, because either the layer itself
+ * or its scrolled clip need to move with that ASR.
* @param aTopLeft The offset between aAnimatedGeometryRoot and
* the reference frame.
- * @param aShouldFixToViewport If true, aAnimatedGeometryRoot is the
- * viewport and we will be adding fixed-pos
- * metadata for this layer because the display
- * item returned true from ShouldFixToViewport.
*/
PaintedLayerData NewPaintedLayerData(nsDisplayItem* aItem,
AnimatedGeometryRoot* aAnimatedGeometryRoot,
- const DisplayItemScrollClip* aScrollClip,
- const nsPoint& aTopLeft,
- bool aShouldFixToViewport);
+ const ActiveScrolledRoot* aASR,
+ const DisplayItemClipChain* aClipChain,
+ const ActiveScrolledRoot* aScrollMetadataASR,
+ const nsPoint& aTopLeft);
/* Build a mask layer to represent the clipping region. Will return null if
* there is no clipping specified or a mask layer cannot be built.
* Builds an ImageLayer for the appropriate backend; the mask is relative to
* aLayer's visible region.
* aLayer is the layer to be clipped.
* relative to the container reference frame
* aRoundedRectClipCount is used when building mask layers for PaintedLayers,
@@ -1369,28 +1376,40 @@ protected:
void SetupMaskLayerForCSSMask(Layer* aLayer, nsDisplayMask* aMaskItem);
already_AddRefed<Layer> CreateMaskLayer(
Layer *aLayer, const DisplayItemClip& aClip,
const Maybe<size_t>& aForAncestorMaskLayer,
uint32_t aRoundedRectClipCount = UINT32_MAX);
bool ChooseAnimatedGeometryRoot(const nsDisplayList& aList,
- AnimatedGeometryRoot **aAnimatedGeometryRoot);
+ AnimatedGeometryRoot** aAnimatedGeometryRoot,
+ const ActiveScrolledRoot** aASR);
nsDisplayListBuilder* mBuilder;
LayerManager* mManager;
FrameLayerBuilder* mLayerBuilder;
nsIFrame* mContainerFrame;
nsIFrame* mContainerReferenceFrame;
AnimatedGeometryRoot* mContainerAnimatedGeometryRoot;
ContainerLayer* mContainerLayer;
nsRect mContainerBounds;
- const DisplayItemScrollClip* mContainerScrollClip;
- const DisplayItemScrollClip* mScrollClipForPerspectiveChild;
+
+ // Due to the way we store scroll annotations in the layer tree, we need to
+ // keep track of three (possibly different) ASRs here.
+ // mContainerASR is the ASR of the container display item that this
+ // ContainerState was created for.
+ // mContainerScrollMetadataASR is the ASR of the leafmost scroll metadata
+ // that's in effect on mContainerLayer.
+ // mContainerCompositorASR is the ASR that mContainerLayer moves with on
+ // the compositor / APZ side, taking into account both the scroll meta data
+ // and the fixed position annotation on itself and its ancestors.
+ const ActiveScrolledRoot* mContainerASR;
+ const ActiveScrolledRoot* mContainerScrollMetadataASR;
+ const ActiveScrolledRoot* mContainerCompositorASR;
#ifdef DEBUG
nsRect mAccumulatedChildBounds;
#endif
ContainerLayerParameters mParameters;
/**
* The region of PaintedLayers that should be invalidated every time
* we recycle one.
*/
@@ -2754,27 +2773,29 @@ PaintedLayerDataNode::AddChildNodeFor(An
mChildren.AppendElement(Move(child));
return mChildren.LastElement().get();
}
template<typename NewPaintedLayerCallbackType>
PaintedLayerData*
PaintedLayerDataNode::FindPaintedLayerFor(const nsIntRect& aVisibleRect,
bool aBackfaceHidden,
- const DisplayItemScrollClip* aScrollClip,
+ const ActiveScrolledRoot* aASR,
+ const DisplayItemClipChain* aClipChain,
NewPaintedLayerCallbackType aNewPaintedLayerCallback)
{
if (!mPaintedLayerDataStack.IsEmpty()) {
PaintedLayerData* lowestUsableLayer = nullptr;
for (auto& data : Reversed(mPaintedLayerDataStack)) {
if (data.mVisibleAboveRegion.Intersects(aVisibleRect)) {
break;
}
if (data.mBackfaceHidden == aBackfaceHidden &&
- data.mScrollClip == aScrollClip) {
+ data.mASR == aASR &&
+ DisplayItemClipChain::Equal(data.mClipChain, aClipChain)) {
lowestUsableLayer = &data;
}
nsIntRegion visibleRegion = data.mVisibleRegion;
// Also check whether the event-regions intersect the visible rect,
// unless we're in an inactive layer, in which case the event-regions
// will be hoisted out into their own layer.
// For performance reasons, we check the intersection with the bounds
// of the event-regions.
@@ -2919,27 +2940,28 @@ PaintedLayerDataTree::AddingOwnLayer(Ani
}
node->SetAllDrawingAbove();
}
}
template<typename NewPaintedLayerCallbackType>
PaintedLayerData*
PaintedLayerDataTree::FindPaintedLayerFor(AnimatedGeometryRoot* aAnimatedGeometryRoot,
- const DisplayItemScrollClip* aScrollClip,
+ const ActiveScrolledRoot* aASR,
+ const DisplayItemClipChain* aClipChain,
const nsIntRect& aVisibleRect,
bool aBackfaceHidden,
NewPaintedLayerCallbackType aNewPaintedLayerCallback)
{
const nsIntRect* bounds = &aVisibleRect;
FinishPotentiallyIntersectingNodes(aAnimatedGeometryRoot, bounds);
PaintedLayerDataNode* node = EnsureNodeFor(aAnimatedGeometryRoot);
PaintedLayerData* data =
- node->FindPaintedLayerFor(aVisibleRect, aBackfaceHidden, aScrollClip,
+ node->FindPaintedLayerFor(aVisibleRect, aBackfaceHidden, aASR, aClipChain,
aNewPaintedLayerCallback);
return data;
}
void
PaintedLayerDataTree::FinishPotentiallyIntersectingNodes(AnimatedGeometryRoot* aAnimatedGeometryRoot,
const nsIntRect* aRect)
{
@@ -3184,21 +3206,24 @@ void ContainerState::FinishPaintedLayerD
: PrepareColorLayer(data);
if (layer) {
NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0,
"Layer already in list???");
NS_ASSERTION(newLayerEntry->mLayer == data->mLayer,
"Painted layer at wrong index");
// Store optimized layer in reserved slot
+ NewLayerEntry* paintedLayerEntry = newLayerEntry;
newLayerEntry = &mNewChildLayers[data->mNewChildLayersIndex + 1];
NS_ASSERTION(!newLayerEntry->mLayer, "Slot already occupied?");
newLayerEntry->mLayer = layer;
newLayerEntry->mAnimatedGeometryRoot = data->mAnimatedGeometryRoot;
- newLayerEntry->mScrollClip = data->mScrollClip;
+ newLayerEntry->mASR = paintedLayerEntry->mASR;
+ newLayerEntry->mClipChain = paintedLayerEntry->mClipChain;
+ newLayerEntry->mScrollMetadataASR = paintedLayerEntry->mScrollMetadataASR;
// Hide the PaintedLayer. We leave it in the layer tree so that we
// can find and recycle it later.
ParentLayerIntRect emptyRect;
data->mLayer->SetClipRect(Some(emptyRect));
data->mLayer->SetVisibleRegion(LayerIntRegion());
data->mLayer->InvalidateRegion(data->mLayer->GetValidRegion().GetBounds());
data->mLayer->SetEventRegions(EventRegions());
@@ -3207,28 +3232,16 @@ void ContainerState::FinishPaintedLayerD
if (!layer) {
// We couldn't optimize to an image layer or a color layer above.
layer = data->mLayer;
layer->SetClipRect(Nothing());
FLB_LOG_PAINTED_LAYER_DECISION(data, " Selected painted layer=%p\n", layer.get());
}
- // If the layer is a fixed background layer, the clip on the fixed background
- // display item was not applied to the opaque region in
- // ContainerState::ComputeOpaqueRect(), but was saved in data->mItemClip.
- // Apply it to the opaque region now. Note that it's important to do this
- // before the opaque region is propagated to the NewLayerEntry below.
- if (data->mSingleItemFixedToViewport && data->mItemClip.HasClip()) {
- nsRect clipRect = data->mItemClip.GetClipRect();
- nsRect insideRoundedCorners = data->mItemClip.ApproximateIntersectInward(clipRect);
- nsIntRect insideRoundedCornersScaled = ScaleToInsidePixels(insideRoundedCorners);
- data->mOpaqueRegion.AndWith(insideRoundedCornersScaled);
- }
-
if (mLayerBuilder->IsBuildingRetainedLayers()) {
newLayerEntry->mVisibleRegion = data->mVisibleRegion;
newLayerEntry->mOpaqueRegion = data->mOpaqueRegion;
newLayerEntry->mHideAllLayersBelow = data->mHideAllLayersBelow;
newLayerEntry->mOpaqueForAnimatedGeometryRootParent = data->mOpaqueForAnimatedGeometryRootParent;
} else {
SetOuterVisibleRegionForLayer(layer, data->mVisibleRegion);
}
@@ -3283,39 +3296,18 @@ void ContainerState::FinishPaintedLayerD
userData->mForcedBackgroundColor = backgroundColor;
userData->mFontSmoothingBackgroundColor = data->mFontSmoothingBackgroundColor;
// use a mask layer for rounded rect clipping.
// data->mCommonClipCount may be -1 if we haven't put any actual
// drawable items in this layer (i.e. it's only catching events).
int32_t commonClipCount;
- // If the layer contains a single item fixed to the viewport, we removed
- // its clip in ProcessDisplayItems() and saved it to set on the layer instead.
- // Set the clip on the layer now.
- if (data->mSingleItemFixedToViewport && data->mItemClip.HasClip()) {
- nsIntRect layerClipRect = ScaleToNearestPixels(data->mItemClip.GetClipRect());
- layerClipRect.MoveBy(mParameters.mOffset);
- // The clip from such an item becomes part of the layer's scrolled clip,
- // and the associated mask layer one of the layer's "ancestor mask layers".
- LayerClip scrolledClip;
- scrolledClip.SetClipRect(ViewAs<ParentLayerPixel>(layerClipRect));
- scrolledClip.SetMaskLayerIndex(
- SetupMaskLayerForScrolledClip(data->mLayer, data->mItemClip));
- data->mLayer->SetScrolledClip(Some(scrolledClip));
- // There is only one item, so all of the clips are in common to all items.
- // data->mCommonClipCount will be zero because we removed the clip from
- // the display item. (It could also be -1 if we're inside an inactive
- // layer tree in which we don't call UpdateCommonClipCount() at all.)
- MOZ_ASSERT(data->mCommonClipCount == -1 || data->mCommonClipCount == 0);
- commonClipCount = data->mItemClip.GetRoundedRectCount();
- } else {
- commonClipCount = std::max(0, data->mCommonClipCount);
- SetupMaskLayer(layer, data->mItemClip, commonClipCount);
- }
+ commonClipCount = std::max(0, data->mCommonClipCount);
+ SetupMaskLayer(layer, data->mItemClip, commonClipCount);
// copy commonClipCount to the entry
FrameLayerBuilder::PaintedLayerItemsEntry* entry = mLayerBuilder->
GetPaintedLayerItemsEntry(static_cast<PaintedLayer*>(layer.get()));
entry->mCommonClipCount = commonClipCount;
} else {
// mask layer for image and color layers
SetupMaskLayer(layer, data->mItemClip);
}
@@ -3626,32 +3618,35 @@ PaintedLayerData::AccumulateEventRegions
// for quick access in FindPaintedLayerFor().
mScaledHitRegionBounds = aState->ScaleToOutsidePixels(mHitRegion.GetBounds());
mScaledMaybeHitRegionBounds = aState->ScaleToOutsidePixels(mMaybeHitRegion.GetBounds());
}
PaintedLayerData
ContainerState::NewPaintedLayerData(nsDisplayItem* aItem,
AnimatedGeometryRoot* aAnimatedGeometryRoot,
- const DisplayItemScrollClip* aScrollClip,
- const nsPoint& aTopLeft,
- bool aShouldFixToViewport)
+ const ActiveScrolledRoot* aASR,
+ const DisplayItemClipChain* aClipChain,
+ const ActiveScrolledRoot* aScrollMetadataASR,
+ const nsPoint& aTopLeft)
{
PaintedLayerData data;
data.mAnimatedGeometryRoot = aAnimatedGeometryRoot;
- data.mScrollClip = aScrollClip;
+ data.mASR = aASR;
+ data.mClipChain = aClipChain,
data.mAnimatedGeometryRootOffset = aTopLeft;
data.mReferenceFrame = aItem->ReferenceFrame();
- data.mSingleItemFixedToViewport = aShouldFixToViewport;
data.mBackfaceHidden = aItem->Frame()->In3DContextAndBackfaceIsHidden();
data.mNewChildLayersIndex = mNewChildLayers.Length();
NewLayerEntry* newLayerEntry = mNewChildLayers.AppendElement();
newLayerEntry->mAnimatedGeometryRoot = aAnimatedGeometryRoot;
- newLayerEntry->mScrollClip = aScrollClip;
+ newLayerEntry->mASR = aASR;
+ newLayerEntry->mScrollMetadataASR = aScrollMetadataASR;
+ newLayerEntry->mClipChain = aClipChain,
// newLayerEntry->mOpaqueRegion is filled in later from
// paintedLayerData->mOpaqueRegion, if necessary.
// Allocate another entry for this layer's optimization to ColorLayer/ImageLayer
mNewChildLayers.AppendElement();
return data;
}
@@ -3741,29 +3736,31 @@ PaintInactiveLayer(nsDisplayListBuilder*
}
/**
* Chooses a single active scrolled root for the entire display list, used
* when we are flattening layers.
*/
bool
ContainerState::ChooseAnimatedGeometryRoot(const nsDisplayList& aList,
- AnimatedGeometryRoot **aAnimatedGeometryRoot)
+ AnimatedGeometryRoot** aAnimatedGeometryRoot,
+ const ActiveScrolledRoot** aASR)
{
for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) {
LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters);
// 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 = item->GetAnimatedGeometryRoot();
+ *aASR = item->GetActiveScrolledRoot();
return true;
}
return false;
}
nsIntRegion
ContainerState::ComputeOpaqueRect(nsDisplayItem* aItem,
AnimatedGeometryRoot* aAnimatedGeometryRoot,
@@ -3817,53 +3814,44 @@ ContainerState::ComputeOpaqueRect(nsDisp
displayport += scrollFrame->GetOffsetToCrossDoc(mContainerReferenceFrame);
if (opaquePixels.Contains(ScaleRegionToNearestPixels(displayport))) {
*aOpaqueForAnimatedGeometryRootParent = true;
}
}
return opaquePixels;
}
-static const DisplayItemScrollClip*
-InnermostScrollClipApplicableToAGR(const DisplayItemScrollClip* aItemScrollClip,
- AnimatedGeometryRoot* aAnimatedGeometryRoot)
-{
- // "Applicable" scroll clips are those that are for nsIScrollableFrames
- // that are ancestors of aAnimatedGeometryRoot or ancestors of aContainerScrollClip.
- // They can be applied to all items sharing this animated geometry root, so
- // instead of applying to the items individually, they can be applied to the
- // whole layer.
- for (const DisplayItemScrollClip* scrollClip = aItemScrollClip;
- scrollClip;
- scrollClip = scrollClip->mParent) {
- nsIFrame* scrolledFrame = scrollClip->mScrollableFrame->GetScrolledFrame();
- if (nsLayoutUtils::IsAncestorFrameCrossDoc(scrolledFrame, *aAnimatedGeometryRoot)) {
- // scrollClip and all its ancestors are applicable.
- return scrollClip;
- }
- }
- return nullptr;
-}
-
Maybe<size_t>
ContainerState::SetupMaskLayerForScrolledClip(Layer* aLayer,
const DisplayItemClip& aClip)
{
if (aClip.GetRoundedRectCount() > 0) {
Maybe<size_t> maskLayerIndex = Some(aLayer->GetAncestorMaskLayerCount());
if (RefPtr<Layer> maskLayer = CreateMaskLayer(aLayer, aClip, maskLayerIndex,
aClip.GetRoundedRectCount())) {
aLayer->AddAncestorMaskLayer(maskLayer);
return maskLayerIndex;
}
// Fall through to |return Nothing()|.
}
return Nothing();
}
+static const ActiveScrolledRoot*
+GetASRForPerspective(const ActiveScrolledRoot* aASR, nsIFrame* aPerspectiveFrame)
+{
+ for (const ActiveScrolledRoot* asr = aASR; asr; asr = asr->mParent) {
+ nsIFrame* scrolledFrame = asr->mScrollableFrame->GetScrolledFrame();
+ if (nsLayoutUtils::IsAncestorFrameCrossDoc(scrolledFrame, aPerspectiveFrame)) {
+ return asr;
+ }
+ }
+ return nullptr;
+}
+
void
ContainerState::SetupMaskLayerForCSSMask(Layer* aLayer,
nsDisplayMask* aMaskItem)
{
MOZ_ASSERT(mManager->IsCompositingCheap());
RefPtr<ImageLayer> maskLayer =
CreateOrRecycleMaskImageLayerFor(MaskLayerKey(aLayer, Nothing()),
@@ -3948,24 +3936,25 @@ ContainerState::SetupMaskLayerForCSSMask
*/
void
ContainerState::ProcessDisplayItems(nsDisplayList* aList)
{
PROFILER_LABEL("ContainerState", "ProcessDisplayItems",
js::ProfileEntry::Category::GRAPHICS);
AnimatedGeometryRoot* lastAnimatedGeometryRoot = mContainerAnimatedGeometryRoot;
+ const ActiveScrolledRoot* lastASR = mContainerASR;
nsPoint lastAGRTopLeft;
nsPoint topLeft(0,0);
// When NO_COMPONENT_ALPHA is set, items will be flattened into a single
// layer, so we need to choose which active scrolled root to use for all
// items.
if (mFlattenToSingleLayer) {
- if (ChooseAnimatedGeometryRoot(*aList, &lastAnimatedGeometryRoot)) {
+ if (ChooseAnimatedGeometryRoot(*aList, &lastAnimatedGeometryRoot, &lastASR)) {
lastAGRTopLeft = (*lastAnimatedGeometryRoot)->GetOffsetToCrossDoc(mContainerReferenceFrame);
}
}
int32_t maxLayers = gfxPrefs::MaxActiveLayers();
int layerCount = 0;
nsDisplayList savedItems;
@@ -4024,76 +4013,48 @@ ContainerState::ProcessDisplayItems(nsDi
LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters);
if (layerState == LAYER_INACTIVE &&
nsDisplayItem::ForceActiveLayers()) {
layerState = LAYER_ACTIVE;
}
bool forceInactive;
AnimatedGeometryRoot* animatedGeometryRoot;
- AnimatedGeometryRoot* animatedGeometryRootForClip = nullptr;
+ const ActiveScrolledRoot* itemASR = nullptr;
+ const DisplayItemClipChain* layerClipChain = nullptr;
if (mFlattenToSingleLayer && layerState != LAYER_ACTIVE_FORCE) {
forceInactive = true;
animatedGeometryRoot = lastAnimatedGeometryRoot;
+ itemASR = lastASR;
topLeft = lastAGRTopLeft;
+ item->FuseClipChainUpTo(mBuilder, mContainerASR);
} else {
forceInactive = false;
if (mManager->IsWidgetLayerManager()) {
animatedGeometryRoot = item->GetAnimatedGeometryRoot();
- animatedGeometryRootForClip = item->AnimatedGeometryRootForScrollMetadata();
+ itemASR = item->GetActiveScrolledRoot();
+ const DisplayItemClipChain* itemClipChain = item->GetClipChain();
+ if (itemClipChain && itemClipChain->mASR == itemASR) {
+ layerClipChain = itemClipChain->mParent;
+ } else {
+ layerClipChain = itemClipChain;
+ }
} else {
// For inactive layer subtrees, splitting content into PaintedLayers
// based on animated geometry roots is pointless. It's more efficient
// to build the minimum number of layers.
animatedGeometryRoot = mContainerAnimatedGeometryRoot;
-
+ itemASR = mContainerASR;
+ item->FuseClipChainUpTo(mBuilder, mContainerASR);
}
topLeft = (*animatedGeometryRoot)->GetOffsetToCrossDoc(mContainerReferenceFrame);
}
- if (!animatedGeometryRootForClip) {
- animatedGeometryRootForClip = animatedGeometryRoot;
- }
-
- const DisplayItemScrollClip* itemScrollClip = item->ScrollClip();
- // Now we need to separate the item's scroll clip chain into those scroll
- // clips that can be applied to the whole layer (i.e. to all items
- // sharing the item's animated geometry root), and those that need to be
- // applied to the item itself.
- const DisplayItemScrollClip* agrScrollClip =
- InnermostScrollClipApplicableToAGR(itemScrollClip, animatedGeometryRootForClip);
- MOZ_ASSERT(DisplayItemScrollClip::IsAncestor(agrScrollClip, itemScrollClip));
-
- if (agrScrollClip != itemScrollClip) {
- // Pick up any scroll clips that should apply to the item and apply them.
- DisplayItemClip clip = item->GetClip();
- for (const DisplayItemScrollClip* scrollClip = itemScrollClip;
- scrollClip && scrollClip != agrScrollClip && scrollClip != mContainerScrollClip;
- scrollClip = scrollClip->mParent) {
- if (scrollClip->mClip) {
- clip.IntersectWith(*scrollClip->mClip);
- }
- }
- item->SetClip(mBuilder, clip);
- }
-
- bool clipMovesWithLayer = (animatedGeometryRoot == animatedGeometryRootForClip);
-
- bool shouldFixToViewport = !clipMovesWithLayer &&
- !(*animatedGeometryRoot)->GetParent() &&
- item->ShouldFixToViewport(mBuilder);
-
- // For items that are fixed to the viewport, remove their clip at the
- // display item level because additional areas could be brought into
- // view by async scrolling. Save the clip so we can set it on the layer
- // instead later.
- DisplayItemClip fixedToViewportClip = DisplayItemClip::NoClip();
- if (shouldFixToViewport) {
- fixedToViewportClip = item->GetClip();
- item->SetClip(mBuilder, DisplayItemClip::NoClip());
- }
+
+ const ActiveScrolledRoot* scrollMetadataASR =
+ layerClipChain ? ActiveScrolledRoot::PickDescendant(itemASR, layerClipChain->mASR) : itemASR;
bool snap;
nsRect itemContent = item->GetBounds(mBuilder, &snap);
if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) {
nsDisplayLayerEventRegions* eventRegions =
static_cast<nsDisplayLayerEventRegions*>(item);
itemContent = eventRegions->GetHitRegionBounds(mBuilder, &snap);
}
@@ -4114,27 +4075,22 @@ ContainerState::ProcessDisplayItems(nsDi
nsRect bounds = itemContent;
bool dummy;
if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) {
bounds = item->GetBounds(mBuilder, &dummy);
if (itemClip.HasClip()) {
bounds.IntersectRect(bounds, itemClip.GetClipRect());
}
}
- bounds = fixedToViewportClip.ApplyNonRoundedIntersection(bounds);
if (!bounds.IsEmpty()) {
- for (const DisplayItemScrollClip* scrollClip = itemScrollClip;
- scrollClip && scrollClip != mContainerScrollClip;
- scrollClip = scrollClip->mParent) {
- if (scrollClip->mClip) {
- if (scrollClip->mIsAsyncScrollable) {
- bounds = scrollClip->mClip->GetClipRect();
- } else {
- bounds = scrollClip->mClip->ApplyNonRoundedIntersection(bounds);
- }
+ if (itemASR != mContainerASR) {
+ const DisplayItemClip* clip = DisplayItemClipChain::ClipForASR(item->GetClipChain(), mContainerASR);
+ MOZ_ASSERT(clip, "the item should have finite bounds with respect to mContainerASR.");
+ if (clip) {
+ bounds = clip->GetClipRect();
}
}
}
((nsRect&)mAccumulatedChildBounds).UnionRect(mAccumulatedChildBounds, bounds);
#endif
nsIntRect itemVisibleRect = itemDrawRect;
// We haven't computed visibility at this point, so item->GetVisibleRect()
@@ -4172,32 +4128,16 @@ ContainerState::ProcessDisplayItems(nsDi
// Note that items without their own layers can't be skipped this
// way, since their PaintedLayer may decide it wants to draw them
// into its buffer even if they're currently covered.
if (itemVisibleRect.IsEmpty() &&
!item->ShouldBuildLayerEvenIfInvisible(mBuilder)) {
continue;
}
- if (mScrollClipForPerspectiveChild) {
- // We are the single transform child item of an nsDisplayPerspective.
- // Our parent forwarded a scroll clip to us. Pick it up.
- // We do this after any clipping has been applied, because this
- // forwarded scroll clip is only used for scrolling (in the form of
- // APZ frame metrics), not for clipping - the clip still belongs on
- // the perspective item.
- MOZ_ASSERT(itemType == nsDisplayItem::TYPE_TRANSFORM);
- MOZ_ASSERT(!itemScrollClip);
- MOZ_ASSERT(!agrScrollClip);
- MOZ_ASSERT(DisplayItemScrollClip::IsAncestor(mContainerScrollClip,
- mScrollClipForPerspectiveChild));
- itemScrollClip = mScrollClipForPerspectiveChild;
- agrScrollClip = mScrollClipForPerspectiveChild;
- }
-
// 3D-transformed layers don't necessarily draw in the order in which
// they're added to their parent container layer.
bool mayDrawOutOfOrder = itemType == nsDisplayItem::TYPE_TRANSFORM &&
(item->Frame()->Combines3DTransformWithAncestors() ||
item->Frame()->Extend3DContext());
// Let mPaintedLayerDataTree know about this item, so that
// FindPaintedLayerFor and FindOpaqueBackgroundColor are aware of this
@@ -4207,71 +4147,95 @@ ContainerState::ProcessDisplayItems(nsDi
// geometry root that we give it, but it can't easily figure about
// overflow:hidden clips on ancestors just by looking at the frame.
// So we'll do a little hand holding and pass the clip instead of the
// visible rect for the two important cases.
nscolor uniformColor = NS_RGBA(0,0,0,0);
nscolor* uniformColorPtr = (mayDrawOutOfOrder || IsInInactiveLayer()) ? nullptr :
&uniformColor;
nsIntRect clipRectUntyped;
- const DisplayItemClip& layerClip = shouldFixToViewport ? fixedToViewportClip : itemClip;
- ParentLayerIntRect layerClipRect;
nsIntRect* clipPtr = nullptr;
- if (layerClip.HasClip()) {
- layerClipRect = ViewAs<ParentLayerPixel>(
- ScaleToNearestPixels(layerClip.GetClipRect()) + mParameters.mOffset);
- clipRectUntyped = layerClipRect.ToUnknownRect();
+ if (itemClip.HasClip()) {
+ clipRectUntyped = clipRect.ToUnknownRect();
clipPtr = &clipRectUntyped;
}
- if (*animatedGeometryRoot == item->Frame() &&
- *animatedGeometryRoot != mBuilder->RootReferenceFrame()) {
+
+ bool hasScrolledClip = layerClipChain && layerClipChain->mClip.HasClip() &&
+ !ActiveScrolledRoot::IsAncestor(layerClipChain->mASR, itemASR);
+
+ if (hasScrolledClip) {
+ // If the clip is scrolled, reserve just the area of the clip for
+ // layerization, so that elements outside the clip can still merge
+ // into the same layer.
+ const ActiveScrolledRoot* clipASR = layerClipChain->mASR;
+ AnimatedGeometryRoot* clipAGR = mBuilder->AnimatedGeometryRootForASR(clipASR);
+ nsIntRect scrolledClipRect =
+ ScaleToNearestPixels(layerClipChain->mClip.GetClipRect()) + mParameters.mOffset;
+ mPaintedLayerDataTree.AddingOwnLayer(clipAGR,
+ &scrolledClipRect,
+ uniformColorPtr);
+ } else if (item->ShouldFixToViewport(mBuilder) && itemClip.HasClip() &&
+ item->AnimatedGeometryRootForScrollMetadata() != animatedGeometryRoot) {
+ // This is basically the same as the case above, but for the non-APZ
+ // case. At the moment, when APZ is off, there is only the root ASR
+ // (because scroll frames without display ports don't create ASRs) and
+ // the whole clip chain is always just one fused clip.
+ AnimatedGeometryRoot* clipAGR = item->AnimatedGeometryRootForScrollMetadata();
+ nsIntRect scrolledClipRect =
+ ScaleToNearestPixels(itemClip.GetClipRect()) + mParameters.mOffset;
+ mPaintedLayerDataTree.AddingOwnLayer(clipAGR,
+ &scrolledClipRect,
+ uniformColorPtr);
+ } else if (*animatedGeometryRoot == item->Frame() &&
+ *animatedGeometryRoot != mBuilder->RootReferenceFrame()) {
// This is the case for scrollbar thumbs, for example. In that case the
// clip we care about is the overflow:hidden clip on the scrollbar.
mPaintedLayerDataTree.AddingOwnLayer(animatedGeometryRoot->mParentAGR,
clipPtr,
uniformColorPtr);
} else if (prerenderedTransform) {
mPaintedLayerDataTree.AddingOwnLayer(animatedGeometryRoot,
clipPtr,
uniformColorPtr);
- } else if (shouldFixToViewport) {
- mPaintedLayerDataTree.AddingOwnLayer(animatedGeometryRootForClip,
- clipPtr,
- uniformColorPtr);
} else {
// Using itemVisibleRect here isn't perfect. itemVisibleRect can be
// larger or smaller than the potential bounds of item's contents in
// animatedGeometryRoot: It's too large if there's a clipped display
// port somewhere among item's contents (see bug 1147673), and it can
// be too small if the contents can move, because it only looks at the
// contents' current bounds and doesn't anticipate any animations.
// Time will tell whether this is good enough, or whether we need to do
// something more sophisticated here.
mPaintedLayerDataTree.AddingOwnLayer(animatedGeometryRoot,
&itemVisibleRect, uniformColorPtr);
}
ContainerLayerParameters params = mParameters;
params.mBackgroundColor = uniformColor;
params.mLayerCreationHint = GetLayerCreationHint(animatedGeometryRoot);
- params.mScrollClip = agrScrollClip;
- params.mScrollClipForPerspectiveChild = nullptr;
+ params.mScrollMetadataASR = ActiveScrolledRoot::PickDescendant(mContainerScrollMetadataASR, scrollMetadataASR);
+ params.mCompositorASR = params.mScrollMetadataASR != mContainerScrollMetadataASR
+ ? params.mScrollMetadataASR
+ : mContainerCompositorASR;
+ if (itemType == nsDisplayItem::TYPE_FIXED_POSITION) {
+ params.mCompositorASR = itemASR;
+ }
if (itemType == nsDisplayItem::TYPE_PERSPECTIVE) {
// Perspective items have a single child item, an nsDisplayTransform.
// If the perspective item is scrolled, but the perspective-inducing
- // frame is outside the scroll frame (indicated by this items AGR
+ // frame is outside the scroll frame (indicated by item->Frame()
// being outside that scroll frame), we have to take special care to
// make APZ scrolling work properly. APZ needs us to put the scroll
// frame's FrameMetrics on our child transform ContainerLayer instead.
- // Our agrScrollClip is the scroll clip that's applicable to our
- // perspective frame, so it won't be the scroll clip for the scrolled
- // frame in the case that we care about, and we'll forward that scroll
- // clip to our child.
- params.mScrollClipForPerspectiveChild = itemScrollClip;
+ // It's worth investigating whether this ASR adjustment can be done at
+ // display item creation time.
+ scrollMetadataASR = GetASRForPerspective(scrollMetadataASR, item->Frame());
+ params.mScrollMetadataASR = scrollMetadataASR;
+ itemASR = scrollMetadataASR;
}
// Just use its layer.
// Set layerContentsVisibleRect.width/height to -1 to indicate we
// currently don't know. If BuildContainerLayerFor gets called by
// item->BuildLayer, this will be set to a proper rect.
nsIntRect layerContentsVisibleRect(0, 0, -1, -1);
params.mLayerContentsVisibleRect = &layerContentsVisibleRect;
@@ -4302,47 +4266,48 @@ ContainerState::ProcessDisplayItems(nsDi
ownLayer->SetPostScale(mParameters.mXScale,
mParameters.mYScale);
}
// Update that layer's clip and visible rects.
NS_ASSERTION(ownLayer->Manager() == mManager, "Wrong manager");
NS_ASSERTION(!ownLayer->HasUserData(&gLayerManagerUserData),
"We shouldn't have a FrameLayerBuilder-managed layer here!");
- NS_ASSERTION(layerClip.HasClip() ||
- layerClip.GetRoundedRectCount() == 0,
+ NS_ASSERTION(itemClip.HasClip() ||
+ itemClip.GetRoundedRectCount() == 0,
"If we have rounded rects, we must have a clip rect");
// It has its own layer. Update that layer's clip and visible rects.
ownLayer->SetClipRect(Nothing());
ownLayer->SetScrolledClip(Nothing());
- if (layerClip.HasClip()) {
- // For layers fixed to the viewport, the clip becomes part of the
- // layer's scrolled clip. Otherwise, it becomes part of the layer clip.
- if (shouldFixToViewport) {
- LayerClip scrolledClip;
- scrolledClip.SetClipRect(layerClipRect);
- if (layerClip.GetRoundedRectCount() > 0) {
- scrolledClip.SetMaskLayerIndex(
- SetupMaskLayerForScrolledClip(ownLayer.get(), layerClip));
- }
- ownLayer->SetScrolledClip(Some(scrolledClip));
- } else {
- ownLayer->SetClipRect(Some(layerClipRect));
-
- // rounded rectangle clipping using mask layers
- // (must be done after visible rect is set on layer)
- if (layerClip.GetRoundedRectCount() > 0) {
- SetupMaskLayer(ownLayer, layerClip);
- }
+ ownLayer->SetAncestorMaskLayers({});
+ if (itemClip.HasClip()) {
+ ownLayer->SetClipRect(Some(clipRect));
+
+ // rounded rectangle clipping using mask layers
+ // (must be done after visible rect is set on layer)
+ if (itemClip.GetRoundedRectCount() > 0) {
+ SetupMaskLayer(ownLayer, itemClip);
}
}
+ if (hasScrolledClip) {
+ const DisplayItemClip& scrolledClip = layerClipChain->mClip;
+ LayerClip scrolledLayerClip;
+ scrolledLayerClip.SetClipRect(ViewAs<ParentLayerPixel>(
+ ScaleToNearestPixels(scrolledClip.GetClipRect()) + mParameters.mOffset));
+ if (scrolledClip.GetRoundedRectCount() > 0) {
+ scrolledLayerClip.SetMaskLayerIndex(
+ SetupMaskLayerForScrolledClip(ownLayer.get(), scrolledClip));
+ }
+ ownLayer->SetScrolledClip(Some(scrolledLayerClip));
+ }
+
if (item->GetType() == nsDisplayItem::TYPE_MASK) {
- MOZ_ASSERT(layerClip.GetRoundedRectCount() == 0);
+ MOZ_ASSERT(itemClip.GetRoundedRectCount() == 0);
nsDisplayMask* maskItem = static_cast<nsDisplayMask*>(item);
SetupMaskLayerForCSSMask(ownLayer, maskItem);
nsDisplayItem* next = aList->GetBottom();
if (next && next->GetType() == nsDisplayItem::TYPE_SCROLL_INFO_LAYER) {
// Since we do build a layer for mask, there is no need for this
// scroll info layer anymore.
@@ -4364,18 +4329,25 @@ ContainerState::ProcessDisplayItems(nsDi
oldContainer->RemoveChild(ownLayer);
}
NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, ownLayer) < 0,
"Layer already in list???");
NewLayerEntry* newLayerEntry = mNewChildLayers.AppendElement();
newLayerEntry->mLayer = ownLayer;
newLayerEntry->mAnimatedGeometryRoot = animatedGeometryRoot;
- newLayerEntry->mScrollClip = agrScrollClip;
+ newLayerEntry->mASR = itemASR;
+ newLayerEntry->mScrollMetadataASR = scrollMetadataASR;
+ newLayerEntry->mClipChain = layerClipChain;
newLayerEntry->mLayerState = layerState;
+ if (itemType == nsDisplayItem::TYPE_FIXED_POSITION) {
+ newLayerEntry->mIsFixedToRootScrollFrame =
+ item->Frame()->StyleDisplay()->mPosition == NS_STYLE_POSITION_FIXED &&
+ nsLayoutUtils::IsReallyFixedPos(item->Frame());
+ }
// Don't attempt to flatten compnent alpha layers that are within
// a forced active layer, or an active transform;
if (itemType == nsDisplayItem::TYPE_TRANSFORM ||
layerState == LAYER_ACTIVE_FORCE) {
newLayerEntry->mPropagateComponentAlphaFlattening = false;
}
// nsDisplayTransform::BuildLayer must set layerContentsVisibleRect.
@@ -4395,17 +4367,17 @@ ContainerState::ProcessDisplayItems(nsDi
// to avoid failure caused by singular transforms.
newLayerEntry->mUntransformedVisibleRegion = true;
newLayerEntry->mVisibleRegion =
item->GetVisibleRectForChildren().ToOutsidePixels(mAppUnitsPerDevPixel);
} else {
newLayerEntry->mVisibleRegion = itemVisibleRegion;
}
newLayerEntry->mOpaqueRegion = ComputeOpaqueRect(item,
- animatedGeometryRoot, layerClip, aList,
+ animatedGeometryRoot, itemClip, aList,
&newLayerEntry->mHideAllLayersBelow,
&newLayerEntry->mOpaqueForAnimatedGeometryRootParent);
} else {
bool useChildrenVisible =
itemType == nsDisplayItem::TYPE_TRANSFORM &&
(item->Frame()->IsPreserve3DLeaf() ||
item->Frame()->HasPerspective());
const nsIntRegion &visible = useChildrenVisible ?
@@ -4432,22 +4404,22 @@ ContainerState::ProcessDisplayItems(nsDi
/**
* No need to allocate geometry for items that aren't
* part of a PaintedLayer.
*/
mLayerBuilder->AddLayerDisplayItem(ownLayer, item, layerState, nullptr);
} else {
PaintedLayerData* paintedLayerData =
- mPaintedLayerDataTree.FindPaintedLayerFor(animatedGeometryRoot, agrScrollClip,
+ mPaintedLayerDataTree.FindPaintedLayerFor(animatedGeometryRoot, itemASR, layerClipChain,
itemVisibleRect,
item->Frame()->In3DContextAndBackfaceIsHidden(),
[&]() {
- return NewPaintedLayerData(item, animatedGeometryRoot, agrScrollClip,
- topLeft, shouldFixToViewport);
+ return NewPaintedLayerData(item, animatedGeometryRoot, itemASR, layerClipChain, scrollMetadataASR,
+ topLeft);
});
if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) {
nsDisplayLayerEventRegions* eventRegions =
static_cast<nsDisplayLayerEventRegions*>(item);
paintedLayerData->AccumulateEventRegions(this, eventRegions);
} else {
// check to see if the new item has rounded rect clips in common with
@@ -4459,23 +4431,16 @@ ContainerState::ProcessDisplayItems(nsDi
animatedGeometryRoot, itemClip, aList,
&paintedLayerData->mHideAllLayersBelow,
&paintedLayerData->mOpaqueForAnimatedGeometryRootParent);
MOZ_ASSERT(nsIntRegion(itemDrawRect).Contains(opaquePixels));
opaquePixels.AndWith(itemVisibleRect);
paintedLayerData->Accumulate(this, item, opaquePixels,
itemVisibleRect, itemClip, layerState);
- // If we removed the clip from the display item above because it's
- // fixed to the viewport, save it on the PaintedLayerData so we can
- // set it on the layer later.
- if (fixedToViewportClip.HasClip()) {
- paintedLayerData->mItemClip = fixedToViewportClip;
- }
-
if (!paintedLayerData->mLayer) {
// Try to recycle the old layer of this display item.
RefPtr<PaintedLayer> layer =
AttemptToRecyclePaintedLayer(animatedGeometryRoot, item, topLeft);
if (layer) {
paintedLayerData->mLayer = layer;
NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0,
@@ -4955,61 +4920,187 @@ FindOpaqueRegionEntry(nsTArray<OpaqueReg
OpaqueRegionEntry* d = &aEntries[i];
if (d->mAnimatedGeometryRoot == aAnimatedGeometryRoot) {
return d;
}
}
return nullptr;
}
+const ActiveScrolledRoot*
+FindDirectChildASR(const ActiveScrolledRoot* aParent, const ActiveScrolledRoot* aDescendant)
+{
+ MOZ_ASSERT(aDescendant, "can't start at the root when looking for a child");
+ MOZ_ASSERT(ActiveScrolledRoot::IsAncestor(aParent, aDescendant));
+ const ActiveScrolledRoot* directChild = aDescendant;
+ while (directChild->mParent != aParent) {
+ directChild = directChild->mParent;
+ MOZ_RELEASE_ASSERT(directChild, "this must not be null");
+ }
+ return directChild;
+}
+
+static FrameMetrics::ViewID
+ViewIDForASR(const ActiveScrolledRoot* aASR)
+{
+ nsIContent* content = aASR->mScrollableFrame->GetScrolledFrame()->GetContent();
+ return nsLayoutUtils::FindOrCreateIDFor(content);
+}
+
+static void
+FixUpFixedPositionLayer(Layer* aLayer,
+ const ActiveScrolledRoot* aTargetASR,
+ const ActiveScrolledRoot* aLeafScrollMetadataASR,
+ const ActiveScrolledRoot* aContainerScrollMetadataASR,
+ const ActiveScrolledRoot* aContainerCompositorASR,
+ bool aIsFixedToRootScrollFrame)
+{
+ if (!aLayer->GetIsFixedPosition()) {
+ return;
+ }
+
+ // Analyze ASRs to figure out if we need to fix up fixedness annotations on
+ // the layer. Fixed annotations are required in multiple cases:
+ // - Sometimes we set scroll metadata on a layer for a scroll frame that we
+ // don't want the layer to be moved by. (We have to do this if there is a
+ // scrolled clip that is moved by that scroll frame.) So we set the fixed
+ // annotation so that the compositor knows that it should ignore that
+ // scroll metadata when determining the layer's position.
+ // - Sometimes there is a scroll meta data on aLayer's parent layer for a
+ // scroll frame that we don't want aLayer to be moved by. The most common
+ // way for this to happen is with containerful root scrolling, where the
+ // scroll metadata for the root scroll frame is on a container layer that
+ // wraps the whole document's contents.
+ // - Sometimes it's just needed for hit testing, i.e. figuring out what
+ // scroll frame should be scrolled by events over the layer.
+ // A fixed layer needs to be annotated with the scroll ID of the scroll frame
+ // that it is *fixed with respect to*, i.e. the outermost scroll frame which
+ // does not move the layer. nsDisplayFixedPosition only ever annotates layers
+ // with the scroll ID of the presshell's root scroll frame, which is
+ // sometimes the wrong thing to do, so we correct it here. Specifically,
+ // it's the wrong thing to do if the fixed frame's containing block is a
+ // transformed frame - in that case, the fixed frame needs to scroll along
+ // with the transformed frame instead of being fixed with respect to the rsf.
+ // (It would be nice to compute the annotation only in one place and get it
+ // right, instead of fixing it up after the fact like this, but this will
+ // need to do for now.)
+ // compositorASR is the ASR that the layer would move with on the compositor
+ // if there were no fixed annotation on it.
+ const ActiveScrolledRoot* compositorASR =
+ aLeafScrollMetadataASR == aContainerScrollMetadataASR
+ ? aContainerCompositorASR
+ : aLeafScrollMetadataASR;
+
+ // The goal of the annotation is to have the layer move with aTargetASR.
+ if (compositorASR && aTargetASR != compositorASR) {
+ // Mark this layer as fixed with respect to the child scroll frame of aTargetASR.
+ aLayer->SetFixedPositionData(
+ ViewIDForASR(FindDirectChildASR(aTargetASR, compositorASR)),
+ aLayer->GetFixedPositionAnchor(),
+ aLayer->GetFixedPositionSides());
+ } else {
+ // Remove the fixed annotation from the layer, unless this layers is fixed
+ // to the document's root scroll frame - in that case, the annotation is
+ // needed for hit testing, because fixed layers in iframes should scroll
+ // the iframe, even though their position is not affected by scrolling in
+ // the iframe. (The APZ hit testing code has a special case for this.)
+ // nsDisplayFixedPosition has annotated this layer with the document's
+ // root scroll frame's scroll id.
+ aLayer->SetIsFixedPosition(aIsFixedToRootScrollFrame);
+ }
+}
+
void
ContainerState::SetupScrollingMetadata(NewLayerEntry* aEntry)
{
if (mFlattenToSingleLayer) {
// animated geometry roots are forced to all match, so we can't
// use them and we don't get async scrolling.
return;
}
if (!mBuilder->IsPaintingToWindow()) {
// async scrolling not possible, and async scrolling info not computed
// for this paint.
return;
}
+ const ActiveScrolledRoot* startASR = aEntry->mScrollMetadataASR;
+ const ActiveScrolledRoot* stopASR = mContainerScrollMetadataASR;
+ if (!ActiveScrolledRoot::IsAncestor(stopASR, startASR)) {
+ if (ActiveScrolledRoot::IsAncestor(startASR, stopASR)) {
+ // startASR and stopASR are in the same branch of the ASR tree, but
+ // startASR is closer to the root. Just start at stopASR so that the loop
+ // below doesn't actually do anything.
+ startASR = stopASR;
+ } else {
+ // startASR and stopASR are in different branches of the
+ // ASR tree. Find a common ancestor and make that the stopASR.
+ // This can happen when there's a scrollable frame inside a fixed layer
+ // which has a scrolled clip. As far as scroll metadata is concerned,
+ // the scroll frame's scroll metadata will be a child of the scroll ID
+ // that scrolls the clip on the fixed layer. But as far as ASRs are
+ // concerned, those two ASRs are siblings, parented to the ASR of the
+ // fixed layer.
+ do {
+ stopASR = stopASR->mParent;
+ } while (!ActiveScrolledRoot::IsAncestor(stopASR, startASR));
+ }
+ }
+
+ FixUpFixedPositionLayer(aEntry->mLayer, aEntry->mASR, startASR,
+ mContainerScrollMetadataASR, mContainerCompositorASR,
+ aEntry->mIsFixedToRootScrollFrame);
+
AutoTArray<ScrollMetadata,2> metricsArray;
if (aEntry->mBaseScrollMetadata) {
metricsArray.AppendElement(*aEntry->mBaseScrollMetadata);
// The base FrameMetrics was not computed by the nsIScrollableframe, so it
// should not have a mask layer.
MOZ_ASSERT(!aEntry->mBaseScrollMetadata->HasMaskLayer());
}
// Any extra mask layers we need to attach to ScrollMetadatas.
// The list may already contain an entry added for the layer's scrolled clip
// so add to it rather than overwriting it (we clear the list when recycling
// a layer).
nsTArray<RefPtr<Layer>> maskLayers(aEntry->mLayer->GetAllAncestorMaskLayers());
- for (const DisplayItemScrollClip* scrollClip = aEntry->mScrollClip;
- scrollClip && scrollClip != mContainerScrollClip;
- scrollClip = scrollClip->mParent) {
- if (!scrollClip->mIsAsyncScrollable) {
- // This scroll clip was created for a scroll frame that didn't know
- // whether it needs to be async scrollable for scroll handoff. It was
- // not activated, so we don't need to create a frame metrics for it.
- continue;
+ // Iterate over the ASR chain and create the corresponding scroll metadatas.
+ // This loop is slightly tricky because the scrollframe-to-clip relationship
+ // is reversed between DisplayItemClipChain and ScrollMetadata:
+ // - DisplayItemClipChain associates the clip with the scroll frame that
+ // this clip is *moved by*, i.e. the clip is moving inside the scroll
+ // frame.
+ // - ScrollMetaData associates the scroll frame with the clip that's
+ // *just outside* the scroll frame, i.e. not moved by the scroll frame
+ // itself.
+ // This discrepancy means that the leaf clip item of the clip chain is never
+ // applied to any scroll meta data. Instead, it was applied earlier as the
+ // layer's clip (or fused with the painted layer contents), or it was applied
+ // as a ScrolledClip on the layer.
+ const DisplayItemClipChain* clipChain = aEntry->mClipChain;
+
+ for (const ActiveScrolledRoot* asr = startASR; asr != stopASR; asr = asr->mParent) {
+ if (!asr) {
+ MOZ_ASSERT_UNREACHABLE("Should have encountered stopASR on the way up.");
+ break;
}
-
- nsIScrollableFrame* scrollFrame = scrollClip->mScrollableFrame;
- const DisplayItemClip* clip = scrollClip->mClip;
+ if (clipChain && clipChain->mASR == asr) {
+ clipChain = clipChain->mParent;
+ }
+
+ nsIScrollableFrame* scrollFrame = asr->mScrollableFrame;
+ const DisplayItemClip* clip =
+ (clipChain && clipChain->mASR == asr->mParent) ? &clipChain->mClip : nullptr;
Maybe<ScrollMetadata> metadata =
- scrollFrame->ComputeScrollMetadata(aEntry->mLayer, mContainerReferenceFrame, mParameters, clip);
+ scrollFrame->ComputeScrollMetadata(aEntry->mLayer, mContainerReferenceFrame,
+ mParameters, clip);
if (!metadata) {
continue;
}
if (clip &&
clip->HasClip() &&
clip->GetRoundedRectCount() > 0)
{
@@ -5095,19 +5186,19 @@ ContainerState::PostprocessRetainedLayer
data->mAnimatedGeometryRoot = animatedGeometryRootToCover;
}
nsIntRegion clippedOpaque = e->mOpaqueRegion;
Maybe<ParentLayerIntRect> clipRect = e->mLayer->GetCombinedClipRect();
if (clipRect) {
clippedOpaque.AndWith(clipRect->ToUnknownRect());
}
- if (e->mLayer->GetIsFixedPosition() && e->mLayer->GetScrolledClip()) {
+ if (e->mLayer->GetScrolledClip()) {
// The clip can move asynchronously, so we can't rely on opaque parts
- // staying in the same place.
+ // staying visible.
clippedOpaque.SetEmpty();
} else if (e->mHideAllLayersBelow) {
hideAll = true;
}
data->mOpaqueRegion.Or(data->mOpaqueRegion, clippedOpaque);
}
if (e->mLayer->GetType() == Layer::TYPE_READBACK) {
@@ -5472,20 +5563,22 @@ FrameLayerBuilder::BuildContainerLayerFo
// Empty layers only have metadata and should never have display items. We
// early exit because later, invalidation will walk up the frame tree to
// determine which painted layer gets invalidated. Since an empty layer
// should never have anything to paint, it should never be invalidated.
NS_ASSERTION(aChildren->IsEmpty(), "Should have no children");
return containerLayer.forget();
}
- const DisplayItemScrollClip* containerScrollClip = aParameters.mScrollClip;
+ const ActiveScrolledRoot* containerASR = aContainerItem ? aContainerItem->GetActiveScrolledRoot() : nullptr;
+ const ActiveScrolledRoot* containerScrollMetadataASR = aParameters.mScrollMetadataASR;
+ const ActiveScrolledRoot* containerCompositorASR = aParameters.mCompositorASR;
ContainerLayerParameters scaleParameters;
- nsRect bounds = aChildren->GetScrollClippedBoundsUpTo(aBuilder, containerScrollClip);
+ nsRect bounds = aChildren->GetClippedBoundsWithRespectToASR(aBuilder, containerASR);
nsRect childrenVisible =
aContainerItem ? aContainerItem->GetVisibleRectForChildren() :
aContainerFrame->GetVisualOverflowRectRelativeToSelf();
if (!ChooseScaleAndSetTransform(this, aBuilder, aContainerFrame,
aContainerItem,
bounds.Intersect(childrenVisible),
aTransform, aParameters,
containerLayer, state, scaleParameters)) {
@@ -5522,17 +5615,18 @@ FrameLayerBuilder::BuildContainerLayerFo
backgroundColor = aParameters.mBackgroundColor;
}
uint32_t flags;
while (true) {
ContainerState state(aBuilder, aManager, aManager->GetLayerBuilder(),
aContainerFrame, aContainerItem, bounds,
containerLayer, scaleParameters, flattenToSingleLayer,
- backgroundColor, containerScrollClip);
+ backgroundColor, containerASR, containerScrollMetadataASR,
+ containerCompositorASR);
state.ProcessDisplayItems(aChildren);
// Set CONTENT_COMPONENT_ALPHA if any of our children have it.
// This is suboptimal ... a child could have text that's over transparent
// pixels in its own layer, but over opaque parts of previous siblings.
bool hasComponentAlphaChildren = false;
bool mayFlatten =
--- a/layout/painting/FrameLayerBuilder.h
+++ b/layout/painting/FrameLayerBuilder.h
@@ -22,17 +22,18 @@
class nsDisplayListBuilder;
class nsDisplayList;
class nsDisplayItem;
class gfxContext;
class nsDisplayItemGeometry;
class nsDisplayMask;
namespace mozilla {
-class DisplayItemScrollClip;
+struct ActiveScrolledRoot;
+struct DisplayItemClipChain;
namespace layers {
class ContainerLayer;
class LayerManager;
class BasicLayerManager;
class PaintedLayer;
class ImageLayer;
} // namespace layers
@@ -53,49 +54,49 @@ public:
};
struct ContainerLayerParameters {
ContainerLayerParameters()
: mXScale(1)
, mYScale(1)
, mLayerContentsVisibleRect(nullptr)
, mBackgroundColor(NS_RGBA(0,0,0,0))
- , mScrollClip(nullptr)
- , mScrollClipForPerspectiveChild(nullptr)
+ , mScrollMetadataASR(nullptr)
+ , mCompositorASR(nullptr)
, mInTransformedSubtree(false)
, mInActiveTransformedSubtree(false)
, mDisableSubpixelAntialiasingInDescendants(false)
, mInLowPrecisionDisplayPort(false)
, mForEventsAndPluginsOnly(false)
, mLayerCreationHint(layers::LayerManager::NONE)
{}
ContainerLayerParameters(float aXScale, float aYScale)
: mXScale(aXScale)
, mYScale(aYScale)
, mLayerContentsVisibleRect(nullptr)
, mBackgroundColor(NS_RGBA(0,0,0,0))
- , mScrollClip(nullptr)
- , mScrollClipForPerspectiveChild(nullptr)
+ , mScrollMetadataASR(nullptr)
+ , mCompositorASR(nullptr)
, mInTransformedSubtree(false)
, mInActiveTransformedSubtree(false)
, mDisableSubpixelAntialiasingInDescendants(false)
, mInLowPrecisionDisplayPort(false)
, mForEventsAndPluginsOnly(false)
, mLayerCreationHint(layers::LayerManager::NONE)
{}
ContainerLayerParameters(float aXScale, float aYScale,
const nsIntPoint& aOffset,
const ContainerLayerParameters& aParent)
: mXScale(aXScale)
, mYScale(aYScale)
, mLayerContentsVisibleRect(nullptr)
, mOffset(aOffset)
, mBackgroundColor(aParent.mBackgroundColor)
- , mScrollClip(aParent.mScrollClip)
- , mScrollClipForPerspectiveChild(aParent.mScrollClipForPerspectiveChild)
+ , mScrollMetadataASR(aParent.mScrollMetadataASR)
+ , mCompositorASR(aParent.mCompositorASR)
, mInTransformedSubtree(aParent.mInTransformedSubtree)
, mInActiveTransformedSubtree(aParent.mInActiveTransformedSubtree)
, mDisableSubpixelAntialiasingInDescendants(aParent.mDisableSubpixelAntialiasingInDescendants)
, mInLowPrecisionDisplayPort(aParent.mInLowPrecisionDisplayPort)
, mForEventsAndPluginsOnly(aParent.mForEventsAndPluginsOnly)
, mLayerCreationHint(aParent.mLayerCreationHint)
{}
@@ -116,20 +117,18 @@ struct ContainerLayerParameters {
*/
nsIntPoint mOffset;
LayerIntPoint Offset() const {
return LayerIntPoint::FromUnknownPoint(mOffset);
}
nscolor mBackgroundColor;
- const DisplayItemScrollClip* mScrollClip;
-
- // usually nullptr, except when building children of an nsDisplayPerspective
- const DisplayItemScrollClip* mScrollClipForPerspectiveChild;
+ const ActiveScrolledRoot* mScrollMetadataASR;
+ const ActiveScrolledRoot* mCompositorASR;
bool mInTransformedSubtree;
bool mInActiveTransformedSubtree;
bool mDisableSubpixelAntialiasingInDescendants;
bool mInLowPrecisionDisplayPort;
bool mForEventsAndPluginsOnly;
layers::LayerManager::PaintedLayerCreationHint mLayerCreationHint;
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -75,17 +75,16 @@
#include "mozilla/EventStateManager.h"
#include "mozilla/RestyleManager.h"
#include "nsCaret.h"
#include "nsISelection.h"
#include "nsDOMTokenList.h"
#include "mozilla/RuleNodeCacheConditions.h"
#include "nsCSSProps.h"
#include "nsPluginFrame.h"
-#include "DisplayItemScrollClip.h"
#include "nsSVGMaskFrame.h"
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
// GetTickCount().
#ifdef GetCurrentTime
#undef GetCurrentTime
#endif
@@ -852,16 +851,17 @@ nsDisplayListBuilder::AutoCurrentActiveS
nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
nsDisplayListBuilderMode aMode, bool aBuildCaret)
: mReferenceFrame(aReferenceFrame),
mIgnoreScrollFrame(nullptr),
mLayerEventRegions(nullptr),
mCurrentTableItem(nullptr),
mCurrentActiveScrolledRoot(nullptr),
+ mCurrentContainerASR(nullptr),
mCurrentFrame(aReferenceFrame),
mCurrentReferenceFrame(aReferenceFrame),
mCurrentAGR(&mRootAGR),
mRootAGR(aReferenceFrame, nullptr),
mUsedAGRBudget(0),
mDirtyRect(-1,-1,-1,-1),
mGlassDisplayItem(nullptr),
mScrollInfoItemsForHoisting(nullptr),
@@ -957,16 +957,26 @@ nsDisplayListBuilder::WrapAGRForFrame(ns
result = new (this) AnimatedGeometryRoot(aAnimatedGeometryRoot, parent);
mFrameToAnimatedGeometryRootMap.Put(aAnimatedGeometryRoot, result);
}
MOZ_ASSERT(!aParent || result->mParentAGR == aParent);
return result;
}
AnimatedGeometryRoot*
+nsDisplayListBuilder::AnimatedGeometryRootForASR(const ActiveScrolledRoot* aASR)
+{
+ if (!aASR) {
+ return GetRootAnimatedGeometryRoot();
+ }
+ nsIFrame* scrolledFrame = aASR->mScrollableFrame->GetScrolledFrame();
+ return FindAnimatedGeometryRootFor(scrolledFrame);
+}
+
+AnimatedGeometryRoot*
nsDisplayListBuilder::FindAnimatedGeometryRootFor(nsIFrame* aFrame)
{
if (!IsPaintingToWindow()) {
return &mRootAGR;
}
if (aFrame == mCurrentFrame) {
return mCurrentAGR;
}
@@ -1032,19 +1042,22 @@ void nsDisplayListBuilder::MarkOutOfFlow
overflowRect.Inflate(nsPresContext::CSSPixelsToAppUnits(32));
}
if (!dirty.IntersectRect(dirty, overflowRect) &&
!(aFrame->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
return;
}
- const DisplayItemClip* oldClip = mClipState.GetClipForContainingBlockDescendants();
- const DisplayItemScrollClip* sc = mClipState.GetCurrentInnermostScrollClip();
- OutOfFlowDisplayData* data = new OutOfFlowDisplayData(oldClip, sc, dirty);
+ // mClipState.GetClipChainForContainingBlockDescendants can return pointers
+ // to objects on the stack, so we need to clone the chain.
+ const DisplayItemClipChain* clipChain =
+ CopyWholeChain(mClipState.GetClipChainForContainingBlockDescendants());
+ const ActiveScrolledRoot* asr = mCurrentActiveScrolledRoot;
+ OutOfFlowDisplayData* data = new OutOfFlowDisplayData(clipChain, asr, dirty);
aFrame->Properties().Set(nsDisplayListBuilder::OutOfFlowDisplayDataProperty(), data);
MarkFrameForDisplay(aFrame, aDirtyFrame);
}
static void UnmarkFrameForDisplay(nsIFrame* aFrame) {
nsPresContext* presContext = aFrame->PresContext();
presContext->PropertyTable()->
@@ -1062,22 +1075,16 @@ nsDisplayListBuilder::~nsDisplayListBuil
NS_ASSERTION(mFramesMarkedForDisplay.Length() == 0,
"All frames should have been unmarked");
NS_ASSERTION(mPresShellStates.Length() == 0,
"All presshells should have been exited");
NS_ASSERTION(!mCurrentTableItem, "No table item should be active");
nsCSSRendering::EndFrameTreesLocked();
- for (DisplayItemClip* c : mDisplayItemClipsToDestroy) {
- c->DisplayItemClip::~DisplayItemClip();
- }
- for (DisplayItemScrollClip* c : mScrollClipsToDestroy) {
- c->DisplayItemScrollClip::~DisplayItemScrollClip();
- }
for (ActiveScrolledRoot* asr : mActiveScrolledRoots) {
asr->ActiveScrolledRoot::~ActiveScrolledRoot();
}
for (DisplayItemClipChain* c : mClipChainsToDestroy) {
c->DisplayItemClipChain::~DisplayItemClipChain();
}
PL_FinishArenaPool(&mPool);
@@ -1250,16 +1257,33 @@ nsDisplayListBuilder::MarkFramesForDispl
if (classList->Contains(NS_LITERAL_STRING("moz-accessiblecaret"))) {
continue;
}
}
}
mFramesMarkedForDisplay.AppendElement(e);
MarkOutOfFlowFrameForDisplay(aDirtyFrame, e, aDirtyRect);
}
+
+ if (!aDirtyFrame->GetParent()) {
+ // This is the viewport frame of aDirtyFrame's presshell.
+ // Store the current display data so that it can be used for fixed
+ // background images.
+ NS_ASSERTION(CurrentPresShellState()->mPresShell ==
+ aDirtyFrame->PresContext()->PresShell(),
+ "Presshell mismatch");
+ MOZ_ASSERT(!CurrentPresShellState()->mFixedBackgroundDisplayData,
+ "already traversed this presshell's root frame?");
+
+ const DisplayItemClipChain* clipChain =
+ CopyWholeChain(mClipState.GetClipChainForContainingBlockDescendants());
+ const ActiveScrolledRoot* asr = mCurrentActiveScrolledRoot;
+ CurrentPresShellState()->mFixedBackgroundDisplayData.emplace(
+ clipChain, asr, aDirtyRect);
+ }
}
/**
* Mark all preserve-3d children with
* NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO to make sure
* nsFrame::BuildDisplayListForChild() would visit them. Also compute
* dirty rect for preserve-3d children.
*
@@ -1372,44 +1396,16 @@ nsDisplayListBuilder::CreateClipChainInt
}
const DisplayItemClipChain*
nsDisplayListBuilder::CopyWholeChain(const DisplayItemClipChain* aClipChain)
{
return CreateClipChainIntersection(nullptr, aClipChain, nullptr);
}
-const DisplayItemClip*
-nsDisplayListBuilder::AllocateDisplayItemClip(const DisplayItemClip& aOriginal)
-{
- void* p = Allocate(sizeof(DisplayItemClip));
- if (!aOriginal.GetRoundedRectCount()) {
- memcpy(p, &aOriginal, sizeof(DisplayItemClip));
- return static_cast<DisplayItemClip*>(p);
- }
-
- DisplayItemClip* c = new (KnownNotNull, p) DisplayItemClip(aOriginal);
- mDisplayItemClipsToDestroy.AppendElement(c);
- return c;
-}
-
-DisplayItemScrollClip*
-nsDisplayListBuilder::AllocateDisplayItemScrollClip(const DisplayItemScrollClip* aParent,
- nsIScrollableFrame* aScrollableFrame,
- const DisplayItemClip* aClip,
- bool aIsAsyncScrollable)
-{
- void* p = Allocate(sizeof(DisplayItemScrollClip));
- DisplayItemScrollClip* c =
- new (KnownNotNull, p) DisplayItemScrollClip(aParent, aScrollableFrame,
- aClip, aIsAsyncScrollable);
- mScrollClipsToDestroy.AppendElement(c);
- return c;
-}
-
const nsIFrame*
nsDisplayListBuilder::FindReferenceFrameFor(const nsIFrame *aFrame,
nsPoint* aOffset)
{
if (aFrame == mCurrentFrame) {
if (aOffset) {
*aOffset = mCurrentOffsetToReferenceFrame;
}
@@ -1554,16 +1550,27 @@ nsDisplayListBuilder::RecomputeCurrentAn
if (parent == mCurrentFrame) {
cached->mParentAGR = mCurrentAGR;
}
}
}
}
}
+static nsRect
+ApplyAllClipNonRoundedIntersection(const DisplayItemClipChain* aClipChain, const nsRect& aRect)
+{
+ nsRect result = aRect;
+ while (aClipChain) {
+ result = aClipChain->mClip.ApplyNonRoundedIntersection(result);
+ aClipChain = aClipChain->mParent;
+ }
+ return result;
+}
+
void
nsDisplayListBuilder::AdjustWindowDraggingRegion(nsIFrame* aFrame)
{
if (!mWindowDraggingAllowed || !IsForPainting()) {
return;
}
const nsStyleUIReset* styleUI = aFrame->StyleUIReset();
@@ -1605,20 +1612,18 @@ nsDisplayListBuilder::AdjustWindowDraggi
// should not be allowed to interfere with the window dragging region. Using
// just the current DisplayItemClip is not enough to cover this case
// completely because clips are reset while building stacking context
// contents, so for example we'd fail to clip frames that have a clip path
// applied to them. But the current dirty rect doesn't get reset in that
// case, so we use it to make this case work.
nsRect borderBox = aFrame->GetRectRelativeToSelf().Intersect(mDirtyRect);
borderBox += ToReferenceFrame(aFrame);
- const DisplayItemClip* clip = ClipState().GetCurrentCombinedClip(this);
- if (clip) {
- borderBox = clip->ApplyNonRoundedIntersection(borderBox);
- }
+ const DisplayItemClipChain* clip = ClipState().GetCurrentCombinedClipChain(this);
+ borderBox = ApplyAllClipNonRoundedIntersection(clip, borderBox);
if (!borderBox.IsEmpty()) {
LayoutDeviceRect devPixelBorderBox =
LayoutDevicePixel::FromAppUnits(borderBox, aFrame->PresContext()->AppUnitsPerDevPixel());
LayoutDeviceRect transformedDevPixelBorderBox =
TransformBy(referenceFrameToRootReferenceFrame, devPixelBorderBox);
transformedDevPixelBorderBox.Round();
LayoutDeviceIntRect transformedDevPixelBorderBoxInt;
if (transformedDevPixelBorderBox.ToIntRect(&transformedDevPixelBorderBoxInt)) {
@@ -1823,32 +1828,26 @@ nsDisplayList::GetBounds(nsDisplayListBu
nsRect bounds;
for (nsDisplayItem* i = GetBottom(); i != nullptr; i = i->GetAbove()) {
bounds.UnionRect(bounds, i->GetClippedBounds(aBuilder));
}
return bounds;
}
nsRect
-nsDisplayList::GetScrollClippedBoundsUpTo(nsDisplayListBuilder* aBuilder,
- const DisplayItemScrollClip* aIncludeScrollClipsUpTo) const {
+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 (r.IsEmpty()) {
- continue;
- }
- for (auto* sc = i->ScrollClip(); sc && sc != aIncludeScrollClipsUpTo; sc = sc->mParent) {
- if (sc->mClip && sc->mClip->HasClip()) {
- if (sc->mIsAsyncScrollable) {
- // Assume the item can move anywhere in the scroll clip's clip rect.
- r = sc->mClip->GetClipRect();
- } else {
- r = sc->mClip->ApplyNonRoundedIntersection(r);
- }
+ 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.");
+ if (clip) {
+ r = clip->GetClipRect();
}
}
bounds.UnionRect(bounds, r);
}
return bounds;
}
nsRect
@@ -1862,17 +1861,17 @@ nsDisplayList::GetVisibleRect() const {
bool
nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion) {
PROFILER_LABEL("nsDisplayList", "ComputeVisibilityForRoot",
js::ProfileEntry::Category::GRAPHICS);
nsRegion r;
- r.And(*aVisibleRegion, GetBounds(aBuilder));
+ r.And(*aVisibleRegion, GetClippedBoundsWithRespectToASR(aBuilder, nullptr));
return ComputeVisibilityForSublist(aBuilder, aVisibleRegion, r.GetBounds());
}
static nsRegion
TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
{
bool snap;
nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap);
@@ -2528,24 +2527,26 @@ void nsDisplayList::SortByContentOrder(n
Sort(IsContentLEQ, aCommonAncestor);
}
void nsDisplayList::Sort(SortLEQ aCmp, void* aClosure) {
::Sort(this, Count(), aCmp, aClosure);
}
nsDisplayItem::nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
- : nsDisplayItem(aBuilder, aFrame, aBuilder->ClipState().GetCurrentInnermostScrollClip())
+ : nsDisplayItem(aBuilder, aFrame,
+ aBuilder->CurrentActiveScrolledRoot())
{}
nsDisplayItem::nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
- const DisplayItemScrollClip* aScrollClip)
+ const ActiveScrolledRoot* aActiveScrolledRoot)
: mFrame(aFrame)
- , mClip(aBuilder->ClipState().GetCurrentCombinedClip(aBuilder))
- , mScrollClip(aScrollClip)
+ , mClipChain(aBuilder->ClipState().GetCurrentCombinedClipChain(aBuilder))
+ , mClip(DisplayItemClipChain::ClipForASR(mClipChain, aActiveScrolledRoot))
+ , mActiveScrolledRoot(aActiveScrolledRoot)
, mAnimatedGeometryRoot(nullptr)
, mForceNotVisible(aBuilder->IsBuildingInvisibleItems())
#ifdef MOZ_DUMP_PAINTING
, mPainted(false)
#endif
{
mReferenceFrame = aBuilder->FindReferenceFrameFor(aFrame, &mToReferenceFrame);
// This can return the wrong result if the item override ShouldFixToViewport(),
@@ -2627,16 +2628,86 @@ nsDisplayItem::RecomputeVisibility(nsDis
return false;
}
nsRegion opaque = TreatAsOpaque(this, aBuilder);
aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque);
return true;
}
+void
+nsDisplayItem::SetClipChain(const DisplayItemClipChain* aClipChain)
+{
+ mClipChain = aClipChain;
+ mClip = DisplayItemClipChain::ClipForASR(aClipChain, mActiveScrolledRoot);
+}
+
+void
+nsDisplayItem::FuseClipChainUpTo(nsDisplayListBuilder* aBuilder, const ActiveScrolledRoot* aASR)
+{
+ const DisplayItemClipChain* sc = mClipChain;
+ DisplayItemClip mergedClip;
+ while (sc && ActiveScrolledRoot::PickDescendant(aASR, sc->mASR) == sc->mASR) {
+ mergedClip.IntersectWith(sc->mClip);
+ sc = sc->mParent;
+ }
+ if (mergedClip.HasClip()) {
+ mClipChain = aBuilder->AllocateDisplayItemClipChain(mergedClip, aASR, sc);
+ mClip = &mClipChain->mClip;
+ } else {
+ mClipChain = nullptr;
+ mClip = nullptr;
+ }
+}
+
+static const DisplayItemClipChain*
+FindCommonAncestorClipForIntersection(const DisplayItemClipChain* aOne,
+ const DisplayItemClipChain* aTwo)
+{
+ for (const ActiveScrolledRoot* asr =
+ ActiveScrolledRoot::PickDescendant(aOne->mASR, aTwo->mASR);
+ asr;
+ asr = asr->mParent) {
+ if (aOne == aTwo) {
+ return aOne;
+ }
+ if (aOne->mASR == asr) {
+ aOne = aOne->mParent;
+ }
+ if (aTwo->mASR == asr) {
+ aTwo = aTwo->mParent;
+ }
+ if (!aOne) {
+ return aTwo;
+ }
+ if (!aTwo) {
+ return aOne;
+ }
+ }
+ return nullptr;
+}
+
+void
+nsDisplayItem::IntersectClip(nsDisplayListBuilder* aBuilder,
+ const DisplayItemClipChain* aOther)
+{
+ if (!aOther) {
+ return;
+ }
+
+ // aOther might be a reference to a clip on the stack. We need to make sure
+ // that CreateClipChainIntersection will allocate the actual intersected
+ // clip in the builder's arena, so for the mClipChain == nullptr case,
+ // we supply nullptr as the common ancestor so that CreateClipChainIntersection
+ // clones the whole chain.
+ const DisplayItemClipChain* ancestorClip =
+ mClipChain ? FindCommonAncestorClipForIntersection(mClipChain, aOther) : nullptr;
+ SetClipChain(aBuilder->CreateClipChainIntersection(ancestorClip, mClipChain, aOther));
+}
+
nsRect
nsDisplayItem::GetClippedBounds(nsDisplayListBuilder* aBuilder)
{
bool snap;
nsRect r = GetBounds(aBuilder, &snap);
return GetClip().ApplyNonRoundedIntersection(r);
}
@@ -2976,18 +3047,18 @@ nsDisplayBackgroundImage::AppendBackgrou
return true;
}
if (!bg) {
aList->AppendToTop(&bgItemList);
return false;
}
- const DisplayItemScrollClip* scrollClip =
- aBuilder->ClipState().GetCurrentInnermostScrollClip();
+ const ActiveScrolledRoot* asr =
+ aBuilder->CurrentActiveScrolledRoot();
bool needBlendContainer = false;
// Passing bg == nullptr in this macro will result in one iteration with
// i = 0.
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, bg->mImage) {
if (bg->mImage.mLayers[i].mImage.IsEmpty()) {
continue;
@@ -2999,41 +3070,77 @@ nsDisplayBackgroundImage::AppendBackgrou
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
if (!aBuilder->IsForEventDelivery()) {
const nsStyleImageLayers::Layer& layer = bg->mImage.mLayers[i];
SetBackgroundClipRegion(clipState, aFrame, toRef,
layer, bgRect, willPaintBorder);
}
+ nsDisplayList thisItemList;
nsDisplayBackgroundImage::InitData bgData =
nsDisplayBackgroundImage::GetInitData(aBuilder, aFrame, i, bgRect, bg,
LayerizeFixed::DO_NOT_LAYERIZE_FIXED_BACKGROUND_IF_AVOIDING_COMPONENT_ALPHA_LAYERS);
- nsDisplayList thisItemList;
if (bgData.shouldFixToViewport) {
- nsDisplayBackgroundImage* bgItem = new (aBuilder) nsDisplayBackgroundImage(bgData);
+
+ auto* displayData = aBuilder->GetCurrentFixedBackgroundDisplayData();
+ nsDisplayListBuilder::AutoBuildingDisplayList
+ buildingDisplayList(aBuilder, aFrame, aBuilder->GetDirtyRect(), false);
+
+ nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
+ if (displayData) {
+ asrSetter.SetCurrentActiveScrolledRoot(
+ displayData->mContainingBlockActiveScrolledRoot);
+ if (nsLayoutUtils::UsesAsyncScrolling(aFrame)) {
+ // Override the dirty rect on the builder to be the dirty rect of
+ // the viewport.
+ // displayData->mDirtyRect is relative to the presshell's viewport
+ // frame (the root frame), and we need it to be relative to aFrame.
+ nsIFrame* rootFrame = aBuilder->CurrentPresShellState()->mPresShell->GetRootFrame();
+ // There cannot be any transforms between aFrame and rootFrame
+ // because then bgData.shouldFixToViewport would have been false.
+ nsRect dirtyRect = displayData->mDirtyRect + aFrame->GetOffsetTo(rootFrame);
+ buildingDisplayList.SetDirtyRect(dirtyRect);
+ }
+ }
+ nsDisplayBackgroundImage* bgItem = nullptr;
+ {
+ // The clip is captured by the nsDisplayFixedPosition, so clear the
+ // clip for the nsDisplayBackgroundImage inside.
+ DisplayListClipState::AutoSaveRestore bgImageClip(aBuilder);
+ bgImageClip.Clear();
+ bgItem = new (aBuilder) nsDisplayBackgroundImage(bgData);
+ }
thisItemList.AppendNewToTop(
nsDisplayFixedPosition::CreateForFixedBackground(aBuilder, aFrame, bgItem, i));
+
} else {
thisItemList.AppendNewToTop(new (aBuilder) nsDisplayBackgroundImage(bgData));
}
if (bg->mImage.mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) {
+ DisplayListClipState::AutoSaveRestore blendClip(aBuilder);
+ blendClip.ClearUpToASR(asr);
+ // asr is scrolled. Even if we wrap a fixed background layer, that's
+ // fine, because the item will have a scrolled clip that limits the
+ // item with respect to asr.
thisItemList.AppendNewToTop(
new (aBuilder) nsDisplayBlendMode(aBuilder, aFrame, &thisItemList,
bg->mImage.mLayers[i].mBlendMode,
- scrollClip, i + 1));
+ asr, i + 1));
}
bgItemList.AppendToTop(&thisItemList);
}
if (needBlendContainer) {
+ DisplayListClipState::AutoSaveRestore blendContainerClip(aBuilder);
+ blendContainerClip.ClearUpToASR(asr);
bgItemList.AppendNewToTop(
- nsDisplayBlendContainer::CreateForBackgroundBlendMode(aBuilder, aFrame, &bgItemList, scrollClip));
+ nsDisplayBlendContainer::CreateForBackgroundBlendMode(aBuilder, aFrame, &bgItemList, asr));
}
aList->AppendToTop(&bgItemList);
return false;
}
// Check that the rounded border of aFrame, added to aToReferenceFrame,
// intersects aRect. Assumes that the unrounded border has already
@@ -3453,23 +3560,16 @@ nsDisplayBackgroundImage::GetBoundsInter
if (!mBackgroundStyle) {
return nsRect();
}
nsRect clipRect = mBackgroundRect;
if (mFrame->GetType() == nsGkAtoms::canvasFrame) {
nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
clipRect = frame->CanvasArea() + ToReferenceFrame();
- } else if (nsLayoutUtils::UsesAsyncScrolling(mFrame) && mShouldFixToViewport) {
- // If this is a background-attachment:fixed image, and APZ is enabled,
- // async scrolling could reveal additional areas of the image, so don't
- // clip it beyond clipping to the document's viewport.
- if (Maybe<nsRect> viewportRect = GetViewportRectRelativeToReferenceFrame(aBuilder, mFrame)) {
- clipRect = clipRect.Union(*viewportRect);
- }
}
const nsStyleImageLayers::Layer& layer = mBackgroundStyle->mImage.mLayers[mLayer];
return nsCSSRendering::GetBackgroundLayerRect(presContext, mFrame,
mBackgroundRect, clipRect, layer,
aBuilder->GetBackgroundPaintFlags());
}
uint32_t
@@ -3749,23 +3849,21 @@ nsDisplayImageContainer::CanOptimizeToIm
}
return true;
}
void
nsDisplayBackgroundColor::ApplyOpacity(nsDisplayListBuilder* aBuilder,
float aOpacity,
- const DisplayItemClip* aClip)
+ const DisplayItemClipChain* aClip)
{
NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
mColor.a = mColor.a * aOpacity;
- if (aClip) {
- IntersectClip(aBuilder, *aClip);
- }
+ IntersectClip(aBuilder, aClip);
}
bool
nsDisplayBackgroundColor::CanApplyOpacity() const
{
return true;
}
@@ -4031,17 +4129,19 @@ nsDisplayLayerEventRegions::AddFrame(nsD
if (!simpleRegions) {
if (nsLayoutUtils::HasNonZeroCorner(aFrame->StyleBorder()->mBorderRadius)) {
borderBoxHasRoundedCorners = true;
} else {
aFrame->AddStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS);
}
}
- const DisplayItemClip* clip = aBuilder->ClipState().GetCurrentCombinedClip(aBuilder);
+ const DisplayItemClip* clip = DisplayItemClipChain::ClipForASR(
+ aBuilder->ClipState().GetCurrentCombinedClipChain(aBuilder),
+ aBuilder->CurrentActiveScrolledRoot());
if (clip) {
borderBox = clip->ApplyNonRoundedIntersection(borderBox);
if (clip->GetRoundedRectCount() > 0) {
borderBoxHasRoundedCorners = true;
}
}
if (borderBoxHasRoundedCorners ||
@@ -4563,23 +4663,23 @@ nsDisplayBoxShadowInner::ComputeVisibili
// Store the actual visible region
mVisibleRegion.And(*aVisibleRegion, mVisibleRect);
return true;
}
nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList)
: nsDisplayWrapList(aBuilder, aFrame, aList,
- aBuilder->ClipState().GetCurrentInnermostScrollClip())
+ aBuilder->CurrentActiveScrolledRoot())
{}
nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
- const DisplayItemScrollClip* aScrollClip)
- : nsDisplayItem(aBuilder, aFrame, aScrollClip)
+ const ActiveScrolledRoot* aActiveScrolledRoot)
+ : nsDisplayItem(aBuilder, aFrame, aActiveScrolledRoot)
, mOverrideZIndex(0)
, mHasZIndexOverride(false)
{
MOZ_COUNT_CTOR(nsDisplayWrapList);
mBaseVisibleRect = mVisibleRect;
mList.AppendToTop(aList);
@@ -4839,19 +4939,19 @@ nsresult nsDisplayWrapper::WrapListsInPl
rv = WrapEachDisplayItem(aBuilder, aLists.PositionedDescendants(), this);
NS_ENSURE_SUCCESS(rv, rv);
// The outlines may not be in-flow
return WrapEachDisplayItem(aBuilder, aLists.Outlines(), this);
}
nsDisplayOpacity::nsDisplayOpacity(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
- const DisplayItemScrollClip* aScrollClip,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
bool aForEventsAndPluginsOnly)
- : nsDisplayWrapList(aBuilder, aFrame, aList, aScrollClip)
+ : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot)
, mOpacity(aFrame->StyleEffects()->mOpacity)
, mForEventsAndPluginsOnly(aForEventsAndPluginsOnly)
{
MOZ_COUNT_CTOR(nsDisplayOpacity);
}
#ifdef NS_BUILD_REFCNT_LOGGING
nsDisplayOpacity::~nsDisplayOpacity() {
@@ -4938,23 +5038,21 @@ nsDisplayOpacity::NeedsActiveLayer(nsDis
SetAnimationPerformanceWarningForTooSmallItem(aFrame, eCSSProperty_opacity);
}
return false;
}
void
nsDisplayOpacity::ApplyOpacity(nsDisplayListBuilder* aBuilder,
float aOpacity,
- const DisplayItemClip* aClip)
+ const DisplayItemClipChain* aClip)
{
NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
mOpacity = mOpacity * aOpacity;
- if (aClip) {
- IntersectClip(aBuilder, *aClip);
- }
+ IntersectClip(aBuilder, aClip);
}
bool
nsDisplayOpacity::CanApplyOpacity() const
{
return true;
}
@@ -5000,18 +5098,26 @@ nsDisplayOpacity::ShouldFlattenAway(nsDi
for (uint32_t i = 0; i < numChildren; i++) {
for (uint32_t j = i+1; j < numChildren; j++) {
if (children[i].bounds.Intersects(children[j].bounds)) {
return false;
}
}
}
+ // When intersecting the children's clip, only intersect with the clip for
+ // our ASR and not with the whole clip chain, because the rest of the clip
+ // chain is usually already set on the children. In fact, opacity items
+ // usually never have their own clip because during display item creation
+ // time we propagated the clip to our contents, so maybe we should just
+ // remove the clip parameter from ApplyOpacity completely.
+ DisplayItemClipChain clip = { GetClip(), mActiveScrolledRoot, nullptr };
+
for (uint32_t i = 0; i < numChildren; i++) {
- children[i].item->ApplyOpacity(aBuilder, mOpacity, mClip);
+ children[i].item->ApplyOpacity(aBuilder, mOpacity, mClip ? &clip : nullptr);
}
return true;
}
nsDisplayItem::LayerState
nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aParameters) {
@@ -5050,36 +5156,34 @@ nsDisplayOpacity::ComputeVisibility(nsDi
bool nsDisplayOpacity::TryMerge(nsDisplayItem* aItem) {
if (aItem->GetType() != TYPE_OPACITY)
return false;
// items for the same content element should be merged into a single
// compositing group
// aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
if (aItem->Frame()->GetContent() != mFrame->GetContent())
return false;
- if (aItem->GetClip() != GetClip())
- return false;
- if (aItem->ScrollClip() != ScrollClip())
+ if (aItem->GetClipChain() != GetClipChain())
return false;
MergeFromTrackingMergedFrames(static_cast<nsDisplayOpacity*>(aItem));
return true;
}
void
nsDisplayOpacity::WriteDebugInfo(std::stringstream& aStream)
{
aStream << " (opacity " << mOpacity << ")";
}
nsDisplayBlendMode::nsDisplayBlendMode(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
uint8_t aBlendMode,
- const DisplayItemScrollClip* aScrollClip,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
uint32_t aIndex)
- : nsDisplayWrapList(aBuilder, aFrame, aList, aScrollClip)
+ : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot)
, mBlendMode(aBlendMode)
, mIndex(aIndex)
{
MOZ_COUNT_CTOR(nsDisplayBlendMode);
}
#ifdef NS_BUILD_REFCNT_LOGGING
nsDisplayBlendMode::~nsDisplayBlendMode() {
@@ -5140,45 +5244,43 @@ bool nsDisplayBlendMode::TryMerge(nsDisp
return false;
nsDisplayBlendMode* item = static_cast<nsDisplayBlendMode*>(aItem);
// items for the same content element should be merged into a single
// compositing group
if (item->Frame()->GetContent() != mFrame->GetContent())
return false;
if (item->mIndex != 0 || mIndex != 0)
return false; // don't merge background-blend-mode items
- if (item->GetClip() != GetClip())
- return false;
- if (item->ScrollClip() != ScrollClip())
+ if (item->GetClipChain() != GetClipChain())
return false;
MergeFromTrackingMergedFrames(item);
return true;
}
/* static */ nsDisplayBlendContainer*
nsDisplayBlendContainer::CreateForMixBlendMode(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
- const DisplayItemScrollClip* aScrollClip)
-{
- return new (aBuilder) nsDisplayBlendContainer(aBuilder, aFrame, aList, aScrollClip, false);
+ const ActiveScrolledRoot* aActiveScrolledRoot)
+{
+ return new (aBuilder) nsDisplayBlendContainer(aBuilder, aFrame, aList, aActiveScrolledRoot, false);
}
/* static */ nsDisplayBlendContainer*
nsDisplayBlendContainer::CreateForBackgroundBlendMode(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
- const DisplayItemScrollClip* aScrollClip)
-{
- return new (aBuilder) nsDisplayBlendContainer(aBuilder, aFrame, aList, aScrollClip, true);
+ const ActiveScrolledRoot* aActiveScrolledRoot)
+{
+ return new (aBuilder) nsDisplayBlendContainer(aBuilder, aFrame, aList, aActiveScrolledRoot, true);
}
nsDisplayBlendContainer::nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
- const DisplayItemScrollClip* aScrollClip,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
bool aIsForBackground)
- : nsDisplayWrapList(aBuilder, aFrame, aList, aScrollClip)
+ : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot)
, mIsForBackground(aIsForBackground)
{
MOZ_COUNT_CTOR(nsDisplayBlendContainer);
}
#ifdef NS_BUILD_REFCNT_LOGGING
nsDisplayBlendContainer::~nsDisplayBlendContainer() {
MOZ_COUNT_DTOR(nsDisplayBlendContainer);
@@ -5217,30 +5319,29 @@ nsDisplayBlendContainer::GetLayerState(n
bool nsDisplayBlendContainer::TryMerge(nsDisplayItem* aItem) {
if (aItem->GetType() != TYPE_BLEND_CONTAINER)
return false;
// items for the same content element should be merged into a single
// compositing group
// aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
if (aItem->Frame()->GetContent() != mFrame->GetContent())
return false;
- if (aItem->GetClip() != GetClip())
- return false;
- if (aItem->ScrollClip() != ScrollClip())
+ if (aItem->GetClipChain() != GetClipChain())
return false;
MergeFromTrackingMergedFrames(static_cast<nsDisplayBlendContainer*>(aItem));
return true;
}
nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
uint32_t aFlags, ViewID aScrollTarget,
float aScrollbarThumbRatio,
bool aForceActive)
- : nsDisplayWrapList(aBuilder, aFrame, aList)
+ : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot)
, mFlags(aFlags)
, mScrollTarget(aScrollTarget)
, mScrollbarThumbRatio(aScrollbarThumbRatio)
, mForceActive(aForceActive)
{
MOZ_COUNT_CTOR(nsDisplayOwnLayer);
}
@@ -5286,17 +5387,17 @@ nsDisplayOwnLayer::BuildLayer(nsDisplayL
mFrame->PresContext()->SetNotifySubDocInvalidationData(layer);
}
return layer.forget();
}
nsDisplaySubDocument::nsDisplaySubDocument(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
uint32_t aFlags)
- : nsDisplayOwnLayer(aBuilder, aFrame, aList, aFlags)
+ : nsDisplayOwnLayer(aBuilder, aFrame, aList, aBuilder->CurrentActiveScrolledRoot(), aFlags)
, mScrollParentId(aBuilder->GetCurrentScrollParentId())
{
MOZ_COUNT_CTOR(nsDisplaySubDocument);
mForceDispatchToContentRegion =
aBuilder->IsBuildingLayerEventRegions() &&
nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(aFrame->PresContext()->PresShell());
}
@@ -5397,17 +5498,18 @@ nsDisplaySubDocument::ComputeVisibility(
nsRegion childVisibleRegion;
// The visible region for the children may be much bigger than the hole we
// are viewing the children from, so that the compositor process has enough
// content to asynchronously pan while content is being refreshed.
childVisibleRegion = displayport + mFrame->GetOffsetToCrossDoc(ReferenceFrame());
nsRect boundedRect =
- childVisibleRegion.GetBounds().Intersect(mList.GetBounds(aBuilder));
+ childVisibleRegion.GetBounds().Intersect(
+ mList.GetClippedBoundsWithRespectToASR(aBuilder, mActiveScrolledRoot));
bool visible = mList.ComputeVisibilityForSublist(
aBuilder, &childVisibleRegion, boundedRect);
// If APZ is enabled then don't allow this computation to influence
// aVisibleRegion, on the assumption that the layer can be asynchronously
// scrolled so we'll definitely need all the content under it.
if (!nsLayoutUtils::UsesAsyncScrolling(mFrame)) {
bool snap;
@@ -5485,30 +5587,31 @@ nsDisplayResolution::BuildLayer(nsDispla
1.0f / presShell->GetResolution());
layer->AsContainerLayer()->SetScaleToResolution(
presShell->ScaleToResolution(), presShell->GetResolution());
return layer.forget();
}
nsDisplayFixedPosition::nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
- nsDisplayList* aList)
- : nsDisplayOwnLayer(aBuilder, aFrame, aList)
+ nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot)
+ : nsDisplayOwnLayer(aBuilder, aFrame, aList, aActiveScrolledRoot)
, mIndex(0)
, mIsFixedBackground(false)
{
MOZ_COUNT_CTOR(nsDisplayFixedPosition);
Init(aBuilder);
}
nsDisplayFixedPosition::nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
nsDisplayList* aList,
uint32_t aIndex)
- : nsDisplayOwnLayer(aBuilder, aFrame, aList)
+ : nsDisplayOwnLayer(aBuilder, aFrame, aList, aBuilder->CurrentActiveScrolledRoot())
, mIndex(aIndex)
, mIsFixedBackground(true)
{
MOZ_COUNT_CTOR(nsDisplayFixedPosition);
Init(aBuilder);
}
void
@@ -5521,21 +5624,16 @@ nsDisplayFixedPosition::Init(nsDisplayLi
}
/* static */ nsDisplayFixedPosition*
nsDisplayFixedPosition::CreateForFixedBackground(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
nsDisplayBackgroundImage* aImage,
uint32_t aIndex)
{
- // Clear clipping on the child item, since we will apply it to the
- // fixed position item as well.
- aImage->SetClip(aBuilder, DisplayItemClip());
- aImage->SetScrollClip(nullptr);
-
nsDisplayList temp;
temp.AppendToTop(aImage);
return new (aBuilder) nsDisplayFixedPosition(aBuilder, aFrame, &temp, aIndex + 1);
}
#ifdef NS_BUILD_REFCNT_LOGGING
@@ -5585,26 +5683,27 @@ nsDisplayFixedPosition::BuildLayer(nsDis
bool nsDisplayFixedPosition::TryMerge(nsDisplayItem* aItem) {
if (aItem->GetType() != TYPE_FIXED_POSITION)
return false;
// Items with the same fixed position frame can be merged.
nsDisplayFixedPosition* other = static_cast<nsDisplayFixedPosition*>(aItem);
if (other->mFrame != mFrame)
return false;
- if (aItem->GetClip() != GetClip())
+ if (aItem->GetClipChain() != GetClipChain())
return false;
MergeFromTrackingMergedFrames(other);
return true;
}
nsDisplayStickyPosition::nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
- nsDisplayList* aList)
- : nsDisplayOwnLayer(aBuilder, aFrame, aList)
+ nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot)
+ : nsDisplayOwnLayer(aBuilder, aFrame, aList, aActiveScrolledRoot)
{
MOZ_COUNT_CTOR(nsDisplayStickyPosition);
}
#ifdef NS_BUILD_REFCNT_LOGGING
nsDisplayStickyPosition::~nsDisplayStickyPosition() {
MOZ_COUNT_DTOR(nsDisplayStickyPosition);
}
@@ -5669,19 +5768,17 @@ nsDisplayStickyPosition::BuildLayer(nsDi
bool nsDisplayStickyPosition::TryMerge(nsDisplayItem* aItem) {
if (aItem->GetType() != TYPE_STICKY_POSITION)
return false;
// Items with the same fixed position frame can be merged.
nsDisplayStickyPosition* other = static_cast<nsDisplayStickyPosition*>(aItem);
if (other->mFrame != mFrame)
return false;
- if (aItem->GetClip() != GetClip())
- return false;
- if (aItem->ScrollClip() != ScrollClip())
+ if (aItem->GetClipChain() != GetClipChain())
return false;
MergeFromTrackingMergedFrames(other);
return true;
}
nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer(
nsDisplayListBuilder* aBuilder,
nsIFrame* aScrolledFrame,
@@ -5916,17 +6013,17 @@ nsDisplayTransform::SetReferenceFrameToA
}
mVisibleRect = aBuilder->GetDirtyRect() + mToReferenceFrame;
}
void
nsDisplayTransform::Init(nsDisplayListBuilder* aBuilder)
{
mHasBounds = false;
- mStoredList.SetClip(aBuilder, DisplayItemClip::NoClip());
+ mStoredList.SetClipChain(nullptr);
mStoredList.SetVisibleRect(mChildrenVisibleRect);
}
nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
nsIFrame *aFrame, nsDisplayList *aList,
const nsRect& aChildrenVisibleRect,
uint32_t aIndex,
bool aAllowAsyncAnimation)
@@ -6897,20 +6994,17 @@ nsDisplayTransform::TryMerge(nsDisplayIt
/* Make sure that we're dealing with two transforms. */
if (aItem->GetType() != TYPE_TRANSFORM)
return false;
/* Check to see that both frames are part of the same content. */
if (aItem->Frame()->GetContent() != mFrame->GetContent())
return false;
- if (aItem->GetClip() != GetClip())
- return false;
-
- if (aItem->ScrollClip() != ScrollClip())
+ if (aItem->GetClipChain() != GetClipChain())
return false;
/* Now, move everything over to this frame and signal that
* we merged things!
*/
mStoredList.MergeFromTrackingMergedFrames(&static_cast<nsDisplayTransform*>(aItem)->mStoredList);
return true;
}
@@ -7127,18 +7221,18 @@ nsCharClipDisplayItem::ComputeInvalidati
!geometry->mBorderRect.IsEqualInterior(GetBorderRect())) {
aInvalidRegion->Or(oldRect, newRect);
}
}
nsDisplaySVGEffects::nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
bool aHandleOpacity,
- const DisplayItemScrollClip* aScrollClip)
- : nsDisplayWrapList(aBuilder, aFrame, aList, aScrollClip)
+ const ActiveScrolledRoot* aActiveScrolledRoot)
+ : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot)
, mEffectsBounds(aFrame->GetVisualOverflowRectRelativeToSelf())
, mHandleOpacity(aHandleOpacity)
{
MOZ_COUNT_CTOR(nsDisplaySVGEffects);
}
nsDisplaySVGEffects::nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
@@ -7346,18 +7440,18 @@ ComputeMaskGeometry(PaintFramesParams& a
ctx.Restore();
aParams.maskRect = result;
}
nsDisplayMask::nsDisplayMask(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
bool aHandleOpacity,
- const DisplayItemScrollClip* aScrollClip)
- : nsDisplaySVGEffects(aBuilder, aFrame, aList, aHandleOpacity, aScrollClip)
+ const ActiveScrolledRoot* aActiveScrolledRoot)
+ : nsDisplaySVGEffects(aBuilder, aFrame, aList, aHandleOpacity, aActiveScrolledRoot)
{
MOZ_COUNT_CTOR(nsDisplayMask);
nsPresContext* presContext = mFrame->PresContext();
uint32_t flags = aBuilder->GetBackgroundPaintFlags() |
nsCSSRendering::PAINTBG_MASK_IMAGE;
const nsStyleSVGReset *svgReset = aFrame->StyleSVGReset();
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, svgReset->mMask) {
@@ -7385,20 +7479,17 @@ bool nsDisplayMask::TryMerge(nsDisplayIt
return false;
// items for the same content element should be merged into a single
// compositing group
// aItem->GetUnderlyingFrame() returns non-null because it's nsDisplaySVGEffects
if (aItem->Frame()->GetContent() != mFrame->GetContent()) {
return false;
}
- if (aItem->GetClip() != GetClip()) {
- return false;
- }
- if (aItem->ScrollClip() != ScrollClip()) {
+ if (aItem->GetClipChain() != GetClipChain()) {
return false;
}
// Do not merge if mFrame has mask. Continuation frames should apply mask
// independently(just like nsDisplayBackgroundImage).
const nsStyleSVGReset *style = mFrame->StyleSVGReset();
if (style->mMask.HasLayerWithImage()) {
return false;
@@ -7501,17 +7592,18 @@ bool nsDisplayMask::ShouldPaintOnMaskLay
}
bool nsDisplayMask::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion)
{
// Our children may be made translucent or arbitrarily deformed so we should
// not allow them to subtract area from aVisibleRegion.
nsRegion childrenVisible(mVisibleRect);
- nsRect r = mVisibleRect.Intersect(mList.GetBounds(aBuilder));
+ nsRect r = mVisibleRect.Intersect(
+ mList.GetClippedBoundsWithRespectToASR(aBuilder, mActiveScrolledRoot));
mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r);
return true;
}
void
nsDisplayMask::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
@@ -7678,20 +7770,17 @@ bool nsDisplayFilter::TryMerge(nsDisplay
}
// items for the same content element should be merged into a single
// compositing group.
// aItem->Frame() returns non-null because it's nsDisplayFilter
if (aItem->Frame()->GetContent() != mFrame->GetContent()) {
return false;
}
- if (aItem->GetClip() != GetClip()) {
- return false;
- }
- if (aItem->ScrollClip() != ScrollClip()) {
+ if (aItem->GetClipChain() != GetClipChain()) {
return false;
}
nsDisplayFilter* other = static_cast<nsDisplayFilter*>(aItem);
MergeFromTrackingMergedFrames(other);
mEffectsBounds.UnionRect(mEffectsBounds,
other->mEffectsBounds + other->mFrame->GetOffsetTo(mFrame));
@@ -7713,17 +7802,18 @@ bool nsDisplayFilter::ComputeVisibility(
nsRect dirtyRect =
nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(mFrame,
mVisibleRect - offset) +
offset;
// Our children may be made translucent or arbitrarily deformed so we should
// not allow them to subtract area from aVisibleRegion.
nsRegion childrenVisible(dirtyRect);
- nsRect r = dirtyRect.Intersect(mList.GetBounds(aBuilder));
+ nsRect r = dirtyRect.Intersect(
+ mList.GetClippedBoundsWithRespectToASR(aBuilder, mActiveScrolledRoot));
mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r);
return true;
}
void
nsDisplayFilter::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -48,17 +48,16 @@ class nsDisplayTableItem;
class nsISelection;
class nsIScrollableFrame;
class nsDisplayLayerEventRegions;
class nsDisplayScrollInfoLayer;
class nsCaret;
namespace mozilla {
class FrameLayerBuilder;
-class DisplayItemScrollClip;
namespace layers {
class Layer;
class ImageLayer;
class ImageContainer;
} // namespace layers
} // namespace mozilla
// A set of blend modes, that never includes OP_OVER (since it's
@@ -276,17 +275,16 @@ class nsDisplayListBuilder {
nsRect mDirtyRect;
};
public:
typedef mozilla::FrameLayerBuilder FrameLayerBuilder;
typedef mozilla::DisplayItemClip DisplayItemClip;
typedef mozilla::DisplayItemClipChain DisplayItemClipChain;
typedef mozilla::DisplayListClipState DisplayListClipState;
- typedef mozilla::DisplayItemScrollClip DisplayItemScrollClip;
typedef mozilla::ActiveScrolledRoot ActiveScrolledRoot;
typedef nsIWidget::ThemeGeometry ThemeGeometry;
typedef mozilla::layers::Layer Layer;
typedef mozilla::layers::FrameMetrics FrameMetrics;
typedef mozilla::layers::FrameMetrics::ViewID ViewID;
typedef mozilla::gfx::Matrix4x4 Matrix4x4;
/**
@@ -756,29 +754,22 @@ public:
const DisplayItemClipChain* aLeafClip2);
/**
* Clone the supplied clip chain's chain items into this builder's arena.
*/
const DisplayItemClipChain* CopyWholeChain(const DisplayItemClipChain* aClipChain);
/**
- * Allocate a new DisplayItemClip in the arena. Will be cleaned up
- * automatically when the arena goes away.
+ * Only used for containerful root scrolling. This is a workaround.
*/
- const DisplayItemClip* AllocateDisplayItemClip(const DisplayItemClip& aOriginal);
-
- /**
- * Allocate a new DisplayItemScrollClip in the arena. Will be cleaned up
- * automatically when the arena goes away.
- */
- DisplayItemScrollClip* AllocateDisplayItemScrollClip(const DisplayItemScrollClip* aParent,
- nsIScrollableFrame* aScrollableFrame,
- const DisplayItemClip* aClip,
- bool aIsAsyncScrollable);
+ void SetActiveScrolledRootForRootScrollframe(const ActiveScrolledRoot* aASR)
+ { mActiveScrolledRootForRootScrollframe = aASR; }
+ const ActiveScrolledRoot* ActiveScrolledRootForRootScrollframe() const
+ { return mActiveScrolledRootForRootScrollframe; }
/**
* Transfer off main thread animations to the layer. May be called
* with aBuilder and aItem both null, but only if the caller has
* already checked that off main thread animations should be sent to
* the layer. When they are both null, the animations are added to
* the layer as pending animations.
*/
@@ -974,50 +965,101 @@ public:
*/
class AutoCurrentActiveScrolledRootSetter;
friend class AutoCurrentActiveScrolledRootSetter;
class AutoCurrentActiveScrolledRootSetter {
public:
explicit AutoCurrentActiveScrolledRootSetter(nsDisplayListBuilder* aBuilder)
: mBuilder(aBuilder)
, mSavedActiveScrolledRoot(aBuilder->mCurrentActiveScrolledRoot)
+ , mContentClipASR(aBuilder->ClipState().GetContentClipASR())
, mDescendantsStartIndex(aBuilder->mActiveScrolledRoots.Length())
, mUsed(false)
{
}
~AutoCurrentActiveScrolledRootSetter()
{
mBuilder->mCurrentActiveScrolledRoot = mSavedActiveScrolledRoot;
}
void SetCurrentActiveScrolledRoot(const ActiveScrolledRoot* aActiveScrolledRoot)
{
MOZ_ASSERT(!mUsed);
+
+ // Set the builder's mCurrentActiveScrolledRoot.
mBuilder->mCurrentActiveScrolledRoot = aActiveScrolledRoot;
+
+ // We also need to adjust the builder's mCurrentContainerASR.
+ // mCurrentContainerASR needs to be an ASR that all the container's
+ // contents have finite bounds with respect to. If aActiveScrolledRoot
+ // is an ancestor ASR of mCurrentContainerASR, that means we need to
+ // set mCurrentContainerASR to aActiveScrolledRoot, because otherwise
+ // the items that will be created with aActiveScrolledRoot wouldn't
+ // have finite bounds with respect to mCurrentContainerASR. There's one
+ // exception, in the case where there's a content clip on the builder
+ // that is scrolled by a descendant ASR of aActiveScrolledRoot. This
+ // content clip will clip all items that are created while this
+ // AutoCurrentActiveScrolledRootSetter exists. This means that the items
+ // created during our lifetime will have finite bounds with respect to
+ // the content clip's ASR, even if the items' actual ASR is an ancestor
+ // of that. And it also means that mCurrentContainerASR only needs to be
+ // set to the content clip's ASR and not all the way to aActiveScrolledRoot.
+ // This case is tested by fixed-pos-scrolled-clip-opacity-layerize.html
+ // and fixed-pos-scrolled-clip-opacity-inside-layerize.html.
+
+ // finiteBoundsASR is the leafmost ASR that all items created during
+ // object's lifetime have finite bounds with respect to.
+ const ActiveScrolledRoot* finiteBoundsASR = ActiveScrolledRoot::PickDescendant(
+ mContentClipASR, aActiveScrolledRoot);
+
+ // mCurrentContainerASR is adjusted so that it's still an ancestor of
+ // finiteBoundsASR.
mBuilder->mCurrentContainerASR = ActiveScrolledRoot::PickAncestor(
- mBuilder->mCurrentContainerASR, aActiveScrolledRoot);
+ mBuilder->mCurrentContainerASR, finiteBoundsASR);
+
mUsed = true;
}
void EnterScrollFrame(nsIScrollableFrame* aScrollableFrame)
{
MOZ_ASSERT(!mUsed);
ActiveScrolledRoot* asr = mBuilder->AllocateActiveScrolledRoot(
mBuilder->mCurrentActiveScrolledRoot, aScrollableFrame);
mBuilder->mCurrentActiveScrolledRoot = asr;
mUsed = true;
}
void InsertScrollFrame(nsIScrollableFrame* aScrollableFrame);
private:
nsDisplayListBuilder* mBuilder;
+ /**
+ * The builder's mCurrentActiveScrolledRoot at construction time which
+ * needs to be restored at destruction time.
+ */
const ActiveScrolledRoot* mSavedActiveScrolledRoot;
+ /**
+ * If there's a content clip on the builder at construction time, then
+ * mContentClipASR is that content clip's ASR, otherwise null. The
+ * assumption is that the content clip doesn't get relaxed while this
+ * object is on the stack.
+ */
+ const ActiveScrolledRoot* mContentClipASR;
+ /**
+ * InsertScrollFrame needs to mutate existing ASRs (those that were
+ * created while this object was on the stack), and mDescendantsStartIndex
+ * makes it easier to skip ASRs that were created in the past.
+ */
size_t mDescendantsStartIndex;
+ /**
+ * Flag to make sure that only one of SetCurrentActiveScrolledRoot /
+ * EnterScrollFrame / InsertScrollFrame is called per instance of this
+ * class.
+ */
bool mUsed;
};
/**
* Keeps track of the innermost ASR that can be used as the ASR for a
* container item that wraps all items that were created while this
* object was on the stack.
* The rule is: all child items of the container item need to have
@@ -1026,17 +1068,19 @@ public:
class AutoContainerASRTracker;
friend class AutoContainerASRTracker;
class AutoContainerASRTracker {
public:
explicit AutoContainerASRTracker(nsDisplayListBuilder* aBuilder)
: mBuilder(aBuilder)
, mSavedContainerASR(aBuilder->mCurrentContainerASR)
{
- mBuilder->mCurrentContainerASR = mBuilder->mCurrentActiveScrolledRoot;
+ mBuilder->mCurrentContainerASR = ActiveScrolledRoot::PickDescendant(
+ mBuilder->ClipState().GetContentClipASR(),
+ mBuilder->mCurrentActiveScrolledRoot);
}
const ActiveScrolledRoot* GetContainerASR()
{
return mBuilder->mCurrentContainerASR;
}
~AutoContainerASRTracker()
@@ -1161,40 +1205,46 @@ public:
return mPreserves3DCtx.mAccumulatedRectLevels;
}
// Helpers for tables
nsDisplayTableItem* GetCurrentTableItem() { return mCurrentTableItem; }
void SetCurrentTableItem(nsDisplayTableItem* aTableItem) { mCurrentTableItem = aTableItem; }
struct OutOfFlowDisplayData {
- OutOfFlowDisplayData(const DisplayItemClip* aContainingBlockClip,
- const DisplayItemScrollClip* aContainingBlockScrollClip,
+ OutOfFlowDisplayData(const DisplayItemClipChain* aContainingBlockClipChain,
+ const ActiveScrolledRoot* aContainingBlockActiveScrolledRoot,
const nsRect &aDirtyRect)
- : mContainingBlockClip(aContainingBlockClip ? *aContainingBlockClip : DisplayItemClip())
- , mContainingBlockScrollClip(aContainingBlockScrollClip)
+ : mContainingBlockClipChain(aContainingBlockClipChain)
+ , mContainingBlockActiveScrolledRoot(aContainingBlockActiveScrolledRoot)
, mDirtyRect(aDirtyRect)
{}
- DisplayItemClip mContainingBlockClip;
- const DisplayItemScrollClip* mContainingBlockScrollClip;
+ const DisplayItemClipChain* mContainingBlockClipChain;
+ const ActiveScrolledRoot* mContainingBlockActiveScrolledRoot;
nsRect mDirtyRect;
};
NS_DECLARE_FRAME_PROPERTY_DELETABLE(OutOfFlowDisplayDataProperty,
OutOfFlowDisplayData)
static OutOfFlowDisplayData* GetOutOfFlowData(nsIFrame* aFrame)
{
return aFrame->Properties().Get(OutOfFlowDisplayDataProperty());
}
nsPresContext* CurrentPresContext() {
return CurrentPresShellState()->mPresShell->GetPresContext();
}
+ OutOfFlowDisplayData* GetCurrentFixedBackgroundDisplayData()
+ {
+ auto& displayData = CurrentPresShellState()->mFixedBackgroundDisplayData;
+ return displayData ? displayData.ptr() : nullptr;
+ }
+
/**
* Accumulates the bounds of box frames that have moz-appearance
* -moz-win-exclude-glass style. Used in setting glass margins on
* Windows.
*
* We set the window opaque region (from which glass margins are computed)
* to the intersection of the glass region specified here and the opaque
* region computed during painting. So the excluded glass region actually
@@ -1314,16 +1364,22 @@ public:
mPreserves3DCtx.mDirtyRect = aDirtyRect;
}
bool IsBuildingInvisibleItems() const { return mBuildingInvisibleItems; }
void SetBuildingInvisibleItems(bool aBuildingInvisibleItems) {
mBuildingInvisibleItems = aBuildingInvisibleItems;
}
+ /**
+ * This is a convenience function to ease the transition until AGRs and ASRs
+ * are unified.
+ */
+ AnimatedGeometryRoot* AnimatedGeometryRootForASR(const ActiveScrolledRoot* aASR);
+
bool HitTestShouldStopAtFirstOpaque() const {
return mHitTestShouldStopAtFirstOpaque;
}
void SetHitTestShouldStopAtFirstOpaque(bool aHitTestShouldStopAtFirstOpaque) {
mHitTestShouldStopAtFirstOpaque = aHitTestShouldStopAtFirstOpaque;
}
private:
@@ -1342,35 +1398,36 @@ private:
*/
nsIFrame* FindAnimatedGeometryRootFrameFor(nsIFrame* aFrame);
friend class nsDisplayCanvasBackgroundImage;
friend class nsDisplayBackgroundImage;
friend class nsDisplayFixedPosition;
AnimatedGeometryRoot* FindAnimatedGeometryRootFor(nsDisplayItem* aItem);
+ friend class nsDisplayItem;
+ AnimatedGeometryRoot* FindAnimatedGeometryRootFor(nsIFrame* aFrame);
+
AnimatedGeometryRoot* WrapAGRForFrame(nsIFrame* aAnimatedGeometryRoot,
AnimatedGeometryRoot* aParent = nullptr);
- friend class nsDisplayItem;
- AnimatedGeometryRoot* FindAnimatedGeometryRootFor(nsIFrame* aFrame);
-
nsDataHashtable<nsPtrHashKey<nsIFrame>, AnimatedGeometryRoot*> mFrameToAnimatedGeometryRootMap;
/**
* Add the current frame to the AGR budget if possible and remember
* the outcome. Subsequent calls will return the same value as
* returned here.
*/
bool AddToAGRBudget(nsIFrame* aFrame);
struct PresShellState {
nsIPresShell* mPresShell;
nsIFrame* mCaretFrame;
nsRect mCaretRect;
+ mozilla::Maybe<OutOfFlowDisplayData> mFixedBackgroundDisplayData;
uint32_t mFirstFrameMarkedForDisplay;
bool mIsBackgroundOnly;
// This is a per-document flag turning off event handling for all content
// in the document, and is set when we enter a subdocument for a pointer-
// events:none frame.
bool mInsidePointerEventsNoneDoc;
};
@@ -1433,20 +1490,19 @@ private:
// The display item for the Windows window glass background, if any
nsDisplayItem* mGlassDisplayItem;
// A temporary list that we append scroll info items to while building
// display items for the contents of frames with SVG effects.
// Only non-null when ShouldBuildScrollInfoItemsForHoisting() is true.
// This is a pointer and not a real nsDisplayList value because the
// nsDisplayList class is defined below this class, so we can't use it here.
nsDisplayList* mScrollInfoItemsForHoisting;
- nsTArray<DisplayItemScrollClip*> mScrollClipsToDestroy;
- nsTArray<DisplayItemClip*> mDisplayItemClipsToDestroy;
nsTArray<ActiveScrolledRoot*> mActiveScrolledRoots;
nsTArray<DisplayItemClipChain*> mClipChainsToDestroy;
+ const ActiveScrolledRoot* mActiveScrolledRootForRootScrollframe;
nsDisplayListBuilderMode mMode;
ViewID mCurrentScrollParentId;
ViewID mCurrentScrollbarTarget;
uint32_t mCurrentScrollbarFlags;
Preserves3DContext mPreserves3DCtx;
uint32_t mPerspectiveItemIndex;
int32_t mSVGEffectsBuildingDepth;
bool mContainsBlendMode;
@@ -1513,39 +1569,39 @@ protected:
*
* Display items belong to a list at all times (except temporarily as they
* move from one list to another).
*/
class nsDisplayItem : public nsDisplayItemLink {
public:
typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
typedef mozilla::DisplayItemClip DisplayItemClip;
- typedef mozilla::DisplayItemScrollClip DisplayItemScrollClip;
typedef mozilla::DisplayItemClipChain DisplayItemClipChain;
typedef mozilla::ActiveScrolledRoot ActiveScrolledRoot;
typedef mozilla::layers::FrameMetrics FrameMetrics;
typedef mozilla::layers::ScrollMetadata ScrollMetadata;
typedef mozilla::layers::FrameMetrics::ViewID ViewID;
typedef mozilla::layers::Layer Layer;
typedef mozilla::layers::LayerManager LayerManager;
typedef mozilla::LayerState LayerState;
// This is never instantiated directly (it has pure virtual methods), so no
// need to count constructors and destructors.
nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
- const DisplayItemScrollClip* aScrollClip);
+ const ActiveScrolledRoot* aActiveScrolledRoot);
/**
* This constructor is only used in rare cases when we need to construct
* temporary items.
*/
explicit nsDisplayItem(nsIFrame* aFrame)
: mFrame(aFrame)
+ , mClipChain(nullptr)
, mClip(nullptr)
- , mScrollClip(nullptr)
+ , mActiveScrolledRoot(nullptr)
, mReferenceFrame(nullptr)
, mAnimatedGeometryRoot(nullptr)
, mForceNotVisible(false)
#ifdef MOZ_DUMP_PAINTING
, mPainted(false)
#endif
{
}
@@ -1954,17 +2010,17 @@ public:
virtual const nsRect& GetVisibleRectForChildren() const { return mVisibleRect; }
/**
* Stores the given opacity value to be applied when drawing. It is an error to
* call this if CanApplyOpacity returned false.
*/
virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
float aOpacity,
- const DisplayItemClip* aClip) {
+ const DisplayItemClipChain* aClip) {
NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity not supported on this type");
}
/**
* Returns true if this display item would return true from ApplyOpacity without
* actually applying the opacity. Otherwise returns false.
*/
virtual bool CanApplyOpacity() const {
return false;
@@ -2037,51 +2093,44 @@ public:
}
virtual bool SupportsOptimizingToImage() { return false; }
const DisplayItemClip& GetClip()
{
return mClip ? *mClip : DisplayItemClip::NoClip();
}
- void SetClip(nsDisplayListBuilder* aBuilder, const DisplayItemClip& aClip)
- {
- if (!aClip.HasClip()) {
- mClip = nullptr;
- return;
- }
- mClip = aBuilder->AllocateDisplayItemClip(aClip);
- }
-
- void IntersectClip(nsDisplayListBuilder* aBuilder, const DisplayItemClip& aClip)
- {
- if (mClip) {
- DisplayItemClip temp = *mClip;
- temp.IntersectWith(aClip);
- SetClip(aBuilder, temp);
- } else {
- SetClip(aBuilder, aClip);
- }
- }
-
- void SetScrollClip(const DisplayItemScrollClip* aScrollClip) { mScrollClip = aScrollClip; }
- const DisplayItemScrollClip* ScrollClip() const { return mScrollClip; }
+ void IntersectClip(nsDisplayListBuilder* aBuilder, const DisplayItemClipChain* aOther);
+
+ void SetActiveScrolledRoot(const ActiveScrolledRoot* aActiveScrolledRoot) { mActiveScrolledRoot = aActiveScrolledRoot; }
+ const ActiveScrolledRoot* GetActiveScrolledRoot() const { return mActiveScrolledRoot; }
+
+ virtual void SetClipChain(const DisplayItemClipChain* aClipChain);
+ const DisplayItemClipChain* GetClipChain() const { return mClipChain; }
+
+ /**
+ * Intersect all clips in our clip chain up to (and including) aASR and set
+ * set the intersection as this item's clip.
+ */
+ void FuseClipChainUpTo(nsDisplayListBuilder* aBuilder,
+ const ActiveScrolledRoot* aASR);
bool BackfaceIsHidden() {
return mFrame->BackfaceIsHidden();
}
protected:
friend class nsDisplayList;
nsDisplayItem() { mAbove = nullptr; }
nsIFrame* mFrame;
+ const DisplayItemClipChain* mClipChain;
const DisplayItemClip* mClip;
- const DisplayItemScrollClip* mScrollClip;
+ const ActiveScrolledRoot* mActiveScrolledRoot;
// Result of FindReferenceFrameFor(mFrame), if mFrame is non-null
const nsIFrame* mReferenceFrame;
struct AnimatedGeometryRoot* 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
@@ -2108,17 +2157,17 @@ protected:
* slow so we don't support it. The methods that need to step downward
* (HitTest(), ComputeVisibility()) internally build a temporary array of all
* the items while they do the downward traversal, so overall they're still
* linear time. We have optimized for efficient AppendToTop() of both
* items and lists, with minimal codesize. AppendToBottom() is efficient too.
*/
class nsDisplayList {
public:
- typedef mozilla::DisplayItemScrollClip DisplayItemScrollClip;
+ typedef mozilla::ActiveScrolledRoot ActiveScrolledRoot;
typedef mozilla::layers::Layer Layer;
typedef mozilla::layers::LayerManager LayerManager;
typedef mozilla::layers::PaintedLayer PaintedLayer;
/**
* Create an empty list.
*/
nsDisplayList()
@@ -2346,28 +2395,30 @@ public:
already_AddRefed<LayerManager> PaintRoot(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx,
uint32_t aFlags);
/**
* Get the bounds. Takes the union of the bounds of all children.
* The result is not cached.
*/
nsRect GetBounds(nsDisplayListBuilder* aBuilder) const;
+
/**
- * Return the union of the scroll clipped bounds of all children. To get the
- * scroll clipped bounds of a child item, we start with the item's clipped
- * bounds and walk its scroll clip chain up to (but not including)
- * aIncludeScrollClipsUpTo, and take each scroll clip into account. For
- * scroll clips from async scrollable frames we assume that the item can move
- * anywhere inside that scroll frame.
- * In other words, the return value from this method includes all pixels that
- * could potentially be covered by items in this list under async scrolling.
+ * Get this list's bounds, respecting clips relative to aASR. The result is
+ * the union of each item's clipped bounds with respect to aASR. That means
+ * that if an item can move asynchronously with an ASR that is a descendant
+ * of aASR, then the clipped bounds with respect to aASR will be the clip of
+ * that item for aASR, because the item can move anywhere inside that clip.
+ * If there is an item in this list which is not bounded with respect to
+ * aASR (i.e. which does not have "finite bounds" with respect to aASR),
+ * then this method trigger an assertion failure.
*/
- nsRect GetScrollClippedBoundsUpTo(nsDisplayListBuilder* aBuilder,
- const DisplayItemScrollClip* aIncludeScrollClipsUpTo) const;
+ nsRect GetClippedBoundsWithRespectToASR(nsDisplayListBuilder* aBuilder,
+ const ActiveScrolledRoot* aASR) const;
+
/**
* Find the topmost display item that returns a non-null frame, and return
* the frame.
*/
void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
nsDisplayItem::HitTestState* aState,
nsTArray<nsIFrame*> *aOutFrames) const;
/**
@@ -3166,17 +3217,17 @@ public:
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) override;
virtual mozilla::Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) override;
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) override;
virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
float aOpacity,
- const DisplayItemClip* aClip) override;
+ const DisplayItemClipChain* aClip) override;
virtual bool CanApplyOpacity() const override;
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override
{
*aSnap = true;
return mBackgroundRect;
}
@@ -3275,23 +3326,21 @@ public:
NS_DISPLAY_DECL_NAME("BoxShadowOuter", TYPE_BOX_SHADOW_OUTER)
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) override;
virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
float aOpacity,
- const DisplayItemClip* aClip) override
+ const DisplayItemClipChain* aClip) override
{
NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
mOpacity = aOpacity;
- if (aClip) {
- IntersectClip(aBuilder, *aClip);
- }
+ IntersectClip(aBuilder, aClip);
}
virtual bool CanApplyOpacity() const override
{
return true;
}
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override
{
@@ -3428,17 +3477,17 @@ public:
nsRect GetHitRegionBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
{
*aSnap = false;
return mHitRegion.GetBounds().Union(mMaybeHitRegion.GetBounds());
}
virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
float aOpacity,
- const DisplayItemClip* aClip) override
+ const DisplayItemClipChain* aClip) override
{
NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
}
virtual bool CanApplyOpacity() const override
{
return true;
}
@@ -3512,32 +3561,32 @@ class nsDisplayWrapList : public nsDispl
public:
/**
* Takes all the items from aList and puts them in our list.
*/
nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList);
nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList,
- const DisplayItemScrollClip* aScrollClip);
+ const ActiveScrolledRoot* aActiveScrolledRoot);
nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayItem* aItem);
nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
: nsDisplayItem(aBuilder, aFrame), mOverrideZIndex(0), mHasZIndexOverride(false)
{
MOZ_COUNT_CTOR(nsDisplayWrapList);
mBaseVisibleRect = mVisibleRect;
}
virtual ~nsDisplayWrapList();
/**
* Call this if the wrapped list is changed.
*/
virtual void UpdateBounds(nsDisplayListBuilder* aBuilder) override
{
- mBounds = mList.GetScrollClippedBoundsUpTo(aBuilder, mScrollClip);
+ mBounds = mList.GetClippedBoundsWithRespectToASR(aBuilder, mActiveScrolledRoot);
// The display list may contain content that's visible outside the visible
// rect (i.e. the current dirty rect) passed in when the item was created.
// This happens when the dirty rect has been restricted to the visual
// overflow rect of a frame for some reason (e.g. when setting up dirty
// rects in nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay), but that
// frame contains placeholders for out-of-flows that aren't descendants of
// the frame.
mVisibleRect.UnionRect(mBaseVisibleRect, mList.GetVisibleRect());
@@ -3671,17 +3720,17 @@ protected:
/**
* The standard display item to paint a stacking context with translucency
* set by the stacking context root frame's 'opacity' style.
*/
class nsDisplayOpacity : public nsDisplayWrapList {
public:
nsDisplayOpacity(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList,
- const DisplayItemScrollClip* aScrollClip,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
bool aForEventsAndPluginsOnly);
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayOpacity();
#endif
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) override;
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
@@ -3703,17 +3752,17 @@ public:
{
if (mForEventsAndPluginsOnly) {
return false;
}
return nsDisplayWrapList::IsInvalid(aRect);
}
virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
float aOpacity,
- const DisplayItemClip* aClip) override;
+ const DisplayItemClipChain* aClip) override;
virtual bool CanApplyOpacity() const override;
virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override;
static bool NeedsActiveLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY)
virtual void WriteDebugInfo(std::stringstream& aStream) override;
bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) override;
@@ -3721,17 +3770,17 @@ private:
float mOpacity;
bool mForEventsAndPluginsOnly;
};
class nsDisplayBlendMode : public nsDisplayWrapList {
public:
nsDisplayBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList, uint8_t aBlendMode,
- const DisplayItemScrollClip* aScrollClip,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
uint32_t aIndex = 0);
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayBlendMode();
#endif
nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) override;
@@ -3763,21 +3812,23 @@ private:
uint8_t mBlendMode;
uint32_t mIndex;
};
class nsDisplayBlendContainer : public nsDisplayWrapList {
public:
static nsDisplayBlendContainer*
CreateForMixBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
- nsDisplayList* aList, const DisplayItemScrollClip* aScrollClip);
+ nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot);
static nsDisplayBlendContainer*
CreateForBackgroundBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
- nsDisplayList* aList, const DisplayItemScrollClip* aScrollClip);
+ nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot);
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayBlendContainer();
#endif
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aContainerParameters) override;
@@ -3792,17 +3843,17 @@ public:
return (mIsForBackground ? 1 << nsDisplayItem::TYPE_BITS : 0) |
nsDisplayItem::GetPerFrameKey();
}
NS_DISPLAY_DECL_NAME("BlendContainer", TYPE_BLEND_CONTAINER)
private:
nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList,
- const DisplayItemScrollClip* aScrollClip,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
bool aIsForBackground);
// Used to distinguish containers created at building stacking
// context or appending background.
bool mIsForBackground;
};
/**
@@ -3830,17 +3881,19 @@ public:
* GENERATE_SCROLLABLE_LAYER : only valid on nsDisplaySubDocument (and
* subclasses), indicates this layer is to be a scrollable layer, so call
* ComputeFrameMetrics, etc.
* @param aScrollTarget when VERTICAL_SCROLLBAR or HORIZONTAL_SCROLLBAR
* is set in the flags, this parameter should be the ViewID of the
* scrollable content this scrollbar is for.
*/
nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
- nsDisplayList* aList, uint32_t aFlags = 0,
+ nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot,
+ uint32_t aFlags = 0,
ViewID aScrollTarget = mozilla::layers::FrameMetrics::NULL_SCROLL_ID,
float aScrollbarThumbRatio = 0.0f,
bool aForceActive = true);
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayOwnLayer();
#endif
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
@@ -3927,17 +3980,18 @@ public:
/**
* A display item used to represent sticky position elements. The contents
* gets its own layer and creates a stacking context, and the layer will have
* position-related metadata set on it.
*/
class nsDisplayStickyPosition : public nsDisplayOwnLayer {
public:
nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
- nsDisplayList* aList);
+ nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot);
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayStickyPosition();
#endif
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aContainerParameters) override;
NS_DISPLAY_DECL_NAME("StickyPosition", TYPE_STICKY_POSITION)
@@ -3948,17 +4002,18 @@ public:
return mozilla::LAYER_ACTIVE;
}
virtual bool TryMerge(nsDisplayItem* aItem) override;
};
class nsDisplayFixedPosition : public nsDisplayOwnLayer {
public:
nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
- nsDisplayList* aList);
+ nsDisplayList* aList,
+ const ActiveScrolledRoot* aActiveScrolledRoot);
static nsDisplayFixedPosition* CreateForFixedBackground(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
nsDisplayBackgroundImage* aImage,
uint32_t aIndex);
#ifdef NS_BUILD_REFCNT_LOGGING
@@ -4089,17 +4144,17 @@ public:
private:
int32_t mAPD, mParentAPD;
};
class nsDisplaySVGEffects: public nsDisplayWrapList {
public:
nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList, bool aHandleOpacity,
- const DisplayItemScrollClip* aScrollClip);
+ const ActiveScrolledRoot* aActiveScrolledRoot);
nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList, bool aHandleOpacity);
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplaySVGEffects();
#endif
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) override;
@@ -4132,17 +4187,17 @@ protected:
*/
class nsDisplayMask : public nsDisplaySVGEffects {
public:
typedef mozilla::layers::ImageLayer ImageLayer;
typedef class mozilla::gfx::DrawTarget DrawTarget;
nsDisplayMask(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList, bool aHandleOpacity,
- const DisplayItemScrollClip* aScrollClip);
+ const ActiveScrolledRoot* aActiveScrolledRoot);
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayMask();
#endif
NS_DISPLAY_DECL_NAME("Mask", TYPE_MASK)
virtual bool TryMerge(nsDisplayItem* aItem) override;
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
--- a/layout/printing/crashtests/crashtests.list
+++ b/layout/printing/crashtests/crashtests.list
@@ -1,4 +1,4 @@
load 509839-1.html
load 509839-2.html
-asserts-if(browserIsRemote,4) asserts-if(stylo,2) load 576878.xhtml # bug 1324645
+load 576878.xhtml
load 793844.html
--- a/layout/xul/nsBoxFrame.cpp
+++ b/layout/xul/nsBoxFrame.cpp
@@ -1339,16 +1339,21 @@ nsBoxFrame::BuildDisplayList(nsDisplayLi
destination.BorderBackground()->AppendNewToTop(new (aBuilder)
nsDisplayGeneric(aBuilder, this, PaintXULDebugBackground,
"XULDebugBackground"));
destination.Outlines()->AppendNewToTop(new (aBuilder)
nsDisplayXULDebug(aBuilder, this));
}
#endif
+ Maybe<nsDisplayListBuilder::AutoContainerASRTracker> contASRTracker;
+ if (forceLayer) {
+ contASRTracker.emplace(aBuilder);
+ }
+
BuildDisplayListForChildren(aBuilder, aDirtyRect, destination);
// see if we have to draw a selection frame around this container
DisplaySelectionOverlay(aBuilder, destination.Content());
if (forceLayer) {
// This is a bit of a hack. Collect up all descendant display items
// and merge them into a single Content() list. This can cause us
@@ -1357,19 +1362,24 @@ nsBoxFrame::BuildDisplayList(nsDisplayLi
nsDisplayList masterList;
masterList.AppendToTop(tempLists.BorderBackground());
masterList.AppendToTop(tempLists.BlockBorderBackgrounds());
masterList.AppendToTop(tempLists.Floats());
masterList.AppendToTop(tempLists.Content());
masterList.AppendToTop(tempLists.PositionedDescendants());
masterList.AppendToTop(tempLists.Outlines());
+ const ActiveScrolledRoot* ownLayerASR = contASRTracker->GetContainerASR();
+
+ DisplayListClipState::AutoSaveRestore ownLayerClipState(aBuilder);
+ ownLayerClipState.ClearUpToASR(ownLayerASR);
+
// Wrap the list to make it its own layer
aLists.Content()->AppendNewToTop(new (aBuilder)
- nsDisplayOwnLayer(aBuilder, this, &masterList));
+ nsDisplayOwnLayer(aBuilder, this, &masterList, ownLayerASR));
}
}
void
nsBoxFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists)
{
--- a/layout/xul/nsSliderFrame.cpp
+++ b/layout/xul/nsSliderFrame.cpp
@@ -358,32 +358,37 @@ nsSliderFrame::BuildDisplayListForChildr
uint32_t flags = 0;
mozilla::layers::FrameMetrics::ViewID scrollTargetId =
mozilla::layers::FrameMetrics::NULL_SCROLL_ID;
aBuilder->GetScrollbarInfo(&scrollTargetId, &flags);
bool thumbGetsLayer = (scrollTargetId != layers::FrameMetrics::NULL_SCROLL_ID);
nsLayoutUtils::SetScrollbarThumbLayerization(thumb, thumbGetsLayer);
if (thumbGetsLayer) {
+ nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
nsDisplayListCollection tempLists;
nsBoxFrame::BuildDisplayListForChildren(aBuilder, aDirtyRect, tempLists);
// This is a bit of a hack. Collect up all descendant display items
// and merge them into a single Content() list.
nsDisplayList masterList;
masterList.AppendToTop(tempLists.BorderBackground());
masterList.AppendToTop(tempLists.BlockBorderBackgrounds());
masterList.AppendToTop(tempLists.Floats());
masterList.AppendToTop(tempLists.Content());
masterList.AppendToTop(tempLists.PositionedDescendants());
masterList.AppendToTop(tempLists.Outlines());
// Wrap the list to make it its own layer.
+ const ActiveScrolledRoot* ownLayerASR = contASRTracker.GetContainerASR();
+ DisplayListClipState::AutoSaveRestore ownLayerClipState(aBuilder);
+ ownLayerClipState.ClearUpToASR(ownLayerASR);
aLists.Content()->AppendNewToTop(new (aBuilder)
- nsDisplayOwnLayer(aBuilder, this, &masterList, flags, scrollTargetId,
+ nsDisplayOwnLayer(aBuilder, this, &masterList, ownLayerASR,
+ flags, scrollTargetId,
GetThumbRatio()));
return;
}
}
nsBoxFrame::BuildDisplayListForChildren(aBuilder, aDirtyRect, aLists);
}