--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -4883,16 +4883,17 @@ PresShell::CreateRangePaintInfo(nsIDOMRa
auto BuildDisplayListForNode = [&] (nsINode* aNode) {
if (MOZ_UNLIKELY(!aNode->IsContent())) {
return;
}
nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame();
// XXX deal with frame being null due to display:contents
for (; frame; frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame)) {
+ info->mBuilder.SetVisibleRect(frame->GetVisualOverflowRect());
info->mBuilder.SetDirtyRect(frame->GetVisualOverflowRect());
frame->BuildDisplayListForStackingContext(&info->mBuilder, &info->mList);
}
};
if (startContainer->NodeType() == nsIDOMNode::TEXT_NODE) {
BuildDisplayListForNode(startContainer);
}
for (; !iter->IsDone(); iter->Next()) {
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3271,17 +3271,19 @@ nsLayoutUtils::GetFramesForArea(nsIFrame
if (aFlags & IGNORE_CROSS_DOC) {
builder.SetDescendIntoSubdocuments(false);
}
builder.SetHitTestShouldStopAtFirstOpaque(aFlags & ONLY_VISIBLE);
builder.EnterPresShell(aFrame);
+ builder.SetVisibleRect(aRect);
builder.SetDirtyRect(aRect);
+
aFrame->BuildDisplayListForStackingContext(&builder, &list);
builder.LeavePresShell(aFrame, nullptr);
#ifdef MOZ_DUMP_PAINTING
if (gDumpEventList) {
fprintf_stderr(stderr, "Event handling --- (%d,%d):\n", aRect.x, aRect.y);
std::stringstream ss;
@@ -3543,32 +3545,32 @@ nsLayoutUtils::AddExtraBackgroundItems(n
// For the viewport frame in print preview/page layout we want to paint
// the grey background behind the page, not the canvas color.
if (frameType == LayoutFrameType::Viewport &&
nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) {
nsRect bounds = nsRect(aBuilder.ToReferenceFrame(aFrame),
aFrame->GetSize());
nsDisplayListBuilder::AutoBuildingDisplayList
- buildingDisplayList(&aBuilder, aFrame, bounds, false);
+ buildingDisplayList(&aBuilder, aFrame, bounds, bounds, false);
presShell->AddPrintPreviewBackgroundItem(aBuilder, aList, aFrame, bounds);
} else if (frameType != LayoutFrameType::Page) {
// For printing, this function is first called on an nsPageFrame, which
// creates a display list with a PageContent item. The PageContent item's
// paint function calls this function on the nsPageFrame's child which is
// an nsPageContentFrame. We only want to add the canvas background color
// item once, for the nsPageContentFrame.
// Add the canvas background color to the bottom of the list. This
// happens after we've built the list so that AddCanvasBackgroundColorItem
// can monkey with the contents if necessary.
nsRect canvasArea = aVisibleRegion.GetBounds();
canvasArea.IntersectRect(aCanvasArea, canvasArea);
nsDisplayListBuilder::AutoBuildingDisplayList
- buildingDisplayList(&aBuilder, aFrame, canvasArea, false);
+ buildingDisplayList(&aBuilder, aFrame, canvasArea, canvasArea, false);
presShell->AddCanvasBackgroundColorItem(
aBuilder, aList, aFrame, canvasArea, aBackstop);
}
}
nsresult
nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
const nsRegion& aDirtyRegion, nscolor aBackstop,
@@ -3623,17 +3625,18 @@ nsLayoutUtils::PaintFrame(gfxContext* aR
builder.IgnorePaintSuppression();
}
nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
if (rootScrollFrame && !aFrame->GetParent()) {
nsIScrollableFrame* rootScrollableFrame = presShell->GetRootScrollFrameAsScrollable();
MOZ_ASSERT(rootScrollableFrame);
nsRect displayPortBase = aFrame->GetVisualOverflowRectRelativeToSelf();
- Unused << rootScrollableFrame->DecideScrollableLayer(&builder, &displayPortBase,
+ nsRect temp = displayPortBase;
+ Unused << rootScrollableFrame->DecideScrollableLayer(&builder, &displayPortBase, &temp,
/* aSetBase = */ true);
}
nsRegion visibleRegion;
if (aFlags & PaintFrameFlags::PAINT_WIDGET_LAYERS) {
// This layer tree will be reused, so we'll need to calculate it
// for the whole "visible" area of the window
//
@@ -3724,16 +3727,17 @@ nsLayoutUtils::PaintFrame(gfxContext* aR
if (dom::Element* element = presShell->GetDocument()->GetDocumentElement()) {
id = nsLayoutUtils::FindOrCreateIDFor(element);
}
}
nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(&builder, id);
builder.SetDirtyRect(dirtyRect);
+ builder.SetVisibleRect(dirtyRect);
aFrame->BuildDisplayListForStackingContext(&builder, &list);
}
AddExtraBackgroundItems(builder, list, aFrame, canvasArea, visibleRegion, aBackstop);
builder.LeavePresShell(aFrame, &list);
if (!record.GetStart().IsNull() && gfxPrefs::LayersDrawFPS()) {
--- a/layout/generic/ViewportFrame.cpp
+++ b/layout/generic/ViewportFrame.cpp
@@ -97,39 +97,41 @@ ShouldInTopLayerForFullscreen(Element* a
}
#endif // DEBUG
static void
BuildDisplayListForTopLayerFrame(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
nsDisplayList* aList)
{
+ nsRect visible;
nsRect dirty;
DisplayListClipState::AutoClipMultiple clipState(aBuilder);
nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
nsDisplayListBuilder::OutOfFlowDisplayData*
savedOutOfFlowData = nsDisplayListBuilder::GetOutOfFlowData(aFrame);
if (savedOutOfFlowData) {
+ visible = savedOutOfFlowData->mVisibleRect;
dirty = savedOutOfFlowData->mDirtyRect;
// This function is called after we've finished building display items for
// the root scroll frame. That means that the content clip from the root
// scroll frame is no longer on aBuilder. However, we need to make sure
// that the display items we build in this function have finite clipped
// bounds with respect to the root ASR, so we restore the *combined clip*
// that we saved earlier. The combined clip will include the clip from the
// root scroll frame.
clipState.SetClipChainForContainingBlockDescendants(
savedOutOfFlowData->mCombinedClipChain);
clipState.ClipContainingBlockDescendantsExtra(
dirty + aBuilder->ToReferenceFrame(aFrame), nullptr);
asrSetter.SetCurrentActiveScrolledRoot(
savedOutOfFlowData->mContainingBlockActiveScrolledRoot);
}
nsDisplayListBuilder::AutoBuildingDisplayList
- buildingForChild(aBuilder, aFrame, dirty,
+ buildingForChild(aBuilder, aFrame, visible, dirty,
aBuilder->IsAtRootOfPseudoStackingContext());
nsDisplayList list(aBuilder);
aFrame->BuildDisplayListForStackingContext(aBuilder, &list);
aList->AppendToTop(&list);
}
void
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -6629,32 +6629,33 @@ DisplayLine(nsDisplayListBuilder* aBuild
nsBlockFrame::LineIterator& aLine,
int32_t aDepth, int32_t& aDrawnLines, const nsDisplayListSet& aLists,
nsBlockFrame* aFrame, TextOverflow* aTextOverflow,
uint32_t aLineNumberForTextOverflow) {
// If the line's combined area (which includes child frames that
// stick outside of the line's bounding box or our bounding box)
// intersects the dirty rect then paint the line.
bool intersect = aLineArea.Intersects(aBuilder->GetDirtyRect());
+ bool visible = aLineArea.Intersects(aBuilder->GetVisibleRect());
#ifdef DEBUG
if (nsBlockFrame::gLamePaintMetrics) {
aDrawnLines++;
}
DebugOutputDrawLine(aDepth, aLine.get(), intersect);
#endif
// The line might contain a placeholder for a visible out-of-flow, in which
// case we need to descend into it. If there is such a placeholder, we will
// have NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO set.
// In particular, we really want to check ShouldDescendIntoFrame()
// on all the frames on the line, but that might be expensive. So
// we approximate it by checking it on aFrame; if it's true for any
// frame in the line, it's also true for aFrame.
bool lineInline = aLine->IsInline();
bool lineMayHaveTextOverflow = aTextOverflow && lineInline;
- if (!intersect && !aBuilder->ShouldDescendIntoFrame(aFrame) &&
+ if (!intersect && !aBuilder->ShouldDescendIntoFrame(aFrame, visible) &&
!lineMayHaveTextOverflow)
return;
// Collect our line's display items in a temporary nsDisplayListCollection,
// so that we can apply any "text-overflow" clipping to the entire collection
// without affecting previous lines.
nsDisplayListCollection collection(aBuilder);
@@ -6729,17 +6730,17 @@ nsBlockFrame::BuildDisplayList(nsDisplay
// intersect with the dirty area.
// In particular, we really want to check ShouldDescendIntoFrame()
// on all our child frames, but that might be expensive. So we
// approximate it by checking it on |this|; if it's true for any
// frame in our child list, it's also true for |this|.
// Also skip the cursor if we're creating text overflow markers,
// since we need to know what line number we're up to in order
// to generate unique display item keys.
- nsLineBox* cursor = (aBuilder->ShouldDescendIntoFrame(this) || textOverflow) ?
+ nsLineBox* cursor = (aBuilder->ShouldDescendIntoFrame(this, true) || textOverflow) ?
nullptr : GetFirstLineContaining(aBuilder->GetDirtyRect().y);
LineIterator line_end = LinesEnd();
if (cursor) {
for (LineIterator line = mLines.begin(cursor);
line != line_end;
++line) {
nsRect lineArea = line->GetVisualOverflowArea();
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -540,22 +540,23 @@ nsCanvasFrame::BuildDisplayList(nsDispla
nsDisplayBackgroundImage::InitData bgData =
nsDisplayBackgroundImage::GetInitData(aBuilder, this, i, bgRect, bg,
nsDisplayBackgroundImage::LayerizeFixed::ALWAYS_LAYERIZE_FIXED_BACKGROUND);
if (bgData.shouldFixToViewport) {
auto* displayData = aBuilder->GetCurrentFixedBackgroundDisplayData();
nsDisplayListBuilder::AutoBuildingDisplayList
- buildingDisplayList(aBuilder, this, aBuilder->GetDirtyRect(), false);
+ buildingDisplayList(aBuilder, this, aBuilder->GetVisibleRect(), aBuilder->GetDirtyRect(), false);
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
if (displayData) {
nsPoint offset = GetOffsetTo(PresContext()->GetPresShell()->GetRootFrame());
+ aBuilder->SetVisibleRect(displayData->mVisibleRect + offset);
aBuilder->SetDirtyRect(displayData->mDirtyRect + offset);
clipState.SetClipChainForContainingBlockDescendants(
displayData->mContainingBlockClipChain);
asrSetter.SetCurrentActiveScrolledRoot(
displayData->mContainingBlockActiveScrolledRoot);
thisItemASR = displayData->mContainingBlockActiveScrolledRoot;
}
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -2370,17 +2370,17 @@ ItemParticipatesIn3DContext(nsIFrame* aA
static void
WrapSeparatorTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aSource, nsDisplayList* aTarget,
int aIndex) {
if (!aSource->IsEmpty()) {
nsDisplayTransform *sepIdItem =
new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aSource,
- aBuilder->GetDirtyRect(), Matrix4x4(), aIndex);
+ aBuilder->GetVisibleRect(), Matrix4x4(), aIndex);
sepIdItem->SetNoExtendContext();
aTarget->AppendToTop(sepIdItem);
}
}
void
nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
nsDisplayList* aList) {
@@ -2428,73 +2428,80 @@ nsIFrame::BuildDisplayListForStackingCon
// Save dirty rect on the builder to avoid being distorted for
// multiple transforms along the chain.
aBuilder->SavePreserves3DRects();
}
// For preserves3d, use the dirty rect already installed on the
// builder, since aDirtyRect maybe distorted for transforms along
// the chain.
+ nsRect visibleRect = aBuilder->GetVisibleRect();
nsRect dirtyRect = aBuilder->GetDirtyRect();
bool inTransform = aBuilder->IsInTransform();
bool isTransformed = IsTransformed(disp, effectSet);
bool hasPerspective = HasPerspective(effectSet);
// reset blend mode so we can keep track if this stacking context needs have
// a nsDisplayBlendContainer. Set the blend mode back when the routine exits
// so we keep track if the parent stacking context needs a container too.
AutoSaveRestoreContainsBlendMode autoRestoreBlendMode(*aBuilder);
aBuilder->SetContainsBlendMode(false);
- nsRect dirtyRectOutsideTransform = dirtyRect;
+ nsRect visibleRectOutsideTransform = visibleRect;
bool allowAsyncAnimation = false;
if (isTransformed) {
const nsRect overflow = GetVisualOverflowRectRelativeToSelf();
nsDisplayTransform::PrerenderDecision decision =
nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder, this, &dirtyRect);
switch (decision) {
case nsDisplayTransform::FullPrerender:
allowAsyncAnimation = true;
+ visibleRect = dirtyRect;
break;
case nsDisplayTransform::PartialPrerender:
allowAsyncAnimation = true;
+ visibleRect = dirtyRect;
MOZ_FALLTHROUGH;
// fall through to the NoPrerender case
case nsDisplayTransform::NoPrerender:
if (overflow.IsEmpty() && !extend3DContext) {
return;
}
// If we're in preserve-3d then grab the dirty rect that was given to the root
// and transform using the combined transform.
if (Combines3DTransformWithAncestors(disp)) {
- dirtyRect = aBuilder->GetPreserves3DRects();
+ dirtyRect = aBuilder->GetPreserves3DRects(&visibleRect);
}
nsRect untransformedDirtyRect;
if (nsDisplayTransform::UntransformRect(dirtyRect, overflow, this,
&untransformedDirtyRect)) {
dirtyRect = untransformedDirtyRect;
+ nsDisplayTransform::UntransformRect(visibleRect, overflow, this, &visibleRect);
} else {
// This should only happen if the transform is singular, in which case nothing is visible anyway
dirtyRect.SetEmpty();
+ visibleRect.SetEmpty();
}
}
inTransform = true;
}
bool usingFilter = StyleEffects()->HasFilters();
bool usingMask = nsSVGIntegrationUtils::UsingMaskOrClipPathForFrame(this);
bool usingSVGEffects = usingFilter || usingMask;
- nsRect dirtyRectOutsideSVGEffects = dirtyRect;
+ nsRect visibleRectOutsideSVGEffects = visibleRect;
nsDisplayList hoistedScrollInfoItemsStorage(aBuilder);
if (usingSVGEffects) {
dirtyRect =
nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, dirtyRect);
+ visibleRect =
+ nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, visibleRect);
aBuilder->EnterSVGEffectsContents(&hoistedScrollInfoItemsStorage);
}
// We build an opacity item if it's not going to be drawn by SVG content, or
// SVG effects. SVG effects won't handle the opacity if we want an active
// layer (for async animations), see
// nsSVGIntegrationsUtils::PaintMaskAndClipPath or
// nsSVGIntegrationsUtils::PaintFilter.
@@ -2506,17 +2513,17 @@ nsIFrame::BuildDisplayListForStackingCon
IsScrollFrameActive(aBuilder,
nsLayoutUtils::GetNearestScrollableFrame(GetParent(),
nsLayoutUtils::SCROLLABLE_SAME_DOC |
nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN));
bool useFixedPosition = disp->mPosition == NS_STYLE_POSITION_FIXED &&
(nsLayoutUtils::IsFixedPosFrameInDisplayPort(this) || BuilderHasScrolledClip(aBuilder));
nsDisplayListBuilder::AutoBuildingDisplayList
- buildingDisplayList(aBuilder, this, dirtyRect, true);
+ buildingDisplayList(aBuilder, this, visibleRect, dirtyRect, true);
// Depending on the effects that are applied to this frame, we can create
// 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,
@@ -2580,16 +2587,17 @@ nsIFrame::BuildDisplayListForStackingCon
CheckForApzAwareEventHandlers(aBuilder, this);
Maybe<nsRect> contentClip =
GetClipPropClipRect(disp, effects, GetSize());
if (contentClip) {
aBuilder->IntersectDirtyRect(*contentClip);
+ aBuilder->IntersectVisibleRect(*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
@@ -2702,17 +2710,17 @@ nsIFrame::BuildDisplayListForStackingCon
if (usingSVGEffects) {
MOZ_ASSERT(usingFilter ||usingMask,
"Beside filter & mask/clip-path, what else effect do we have?");
if (clipCapturedBy == ContainerItemType::eFilter) {
clipState.Restore();
}
// Revert to the post-filter dirty rect.
- aBuilder->SetDirtyRect(dirtyRectOutsideSVGEffects);
+ aBuilder->SetVisibleRect(visibleRectOutsideSVGEffects);
// 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
// filter display item.
bool handleOpacity = !usingMask && !useOpacity;
@@ -2735,17 +2743,17 @@ nsIFrame::BuildDisplayListForStackingCon
// 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()) {
+ if (useOpacity) {
// 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.ClearUpToASR(containerItemASR);
resultList.AppendNewToTop(
new (aBuilder) nsDisplayOpacity(aBuilder, this, &resultList,
containerItemASR,
@@ -2758,17 +2766,17 @@ nsIFrame::BuildDisplayListForStackingCon
*
* 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,
* we can skip this step, as the computed transform will already include our own.
*
* We also traverse into sublists created by nsDisplayWrapList, so that we find all the
* correct children.
*/
- if (isTransformed && !resultList.IsEmpty() && extend3DContext) {
+ if (isTransformed && extend3DContext) {
// Install dummy nsDisplayTransform as a leaf containing
// descendants not participating this 3D rendering context.
nsDisplayList nonparticipants(aBuilder);
nsDisplayList participants(aBuilder);
int index = 1;
while (nsDisplayItem* item = resultList.RemoveBottom()) {
if (ItemParticipatesIn3DContext(this, item) && !item->GetClip().HasClip()) {
@@ -2785,38 +2793,38 @@ nsIFrame::BuildDisplayListForStackingCon
// \see ContainerLayer::DefaultComputeEffectiveTransforms().
nonparticipants.AppendToTop(item);
}
}
WrapSeparatorTransform(aBuilder, this, &nonparticipants, &participants, index++);
resultList.AppendToTop(&participants);
}
- if (isTransformed && !resultList.IsEmpty()) {
+ if (isTransformed) {
if (clipCapturedBy == ContainerItemType::eTransform) {
// Restore clip state now so nsDisplayTransform is clipped properly.
clipState.Restore();
}
// Revert to the dirtyrect coming in from the parent, without our transform
// taken into account.
- aBuilder->SetDirtyRect(dirtyRectOutsideTransform);
+ aBuilder->SetVisibleRect(visibleRectOutsideTransform);
// 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;
if (this != aBuilder->RootReferenceFrame()) {
outerReferenceFrame =
aBuilder->FindReferenceFrameFor(GetParent(), &toOuterReferenceFrame);
}
buildingDisplayList.SetReferenceFrameAndCurrentOffset(outerReferenceFrame,
GetOffsetToCrossDoc(outerReferenceFrame));
nsDisplayTransform *transformItem =
new (aBuilder) nsDisplayTransform(aBuilder, this,
- &resultList, dirtyRect, 0,
+ &resultList, visibleRect, 0,
allowAsyncAnimation);
resultList.AppendNewToTop(transformItem);
if (hasPerspective) {
if (clipCapturedBy == ContainerItemType::ePerspective) {
clipState.Restore();
}
resultList.AppendNewToTop(
@@ -2865,17 +2873,17 @@ nsIFrame::BuildDisplayListForStackingCon
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()) {
+ if (useBlendMode) {
DisplayListClipState::AutoSaveRestore blendModeClipState(aBuilder);
blendModeClipState.ClearUpToASR(containerItemASR);
resultList.AppendNewToTop(
new (aBuilder) nsDisplayBlendMode(aBuilder, this, &resultList,
effects->mMixBlendMode,
containerItemASR));
}
@@ -2911,17 +2919,17 @@ WrapInWrapList(nsDisplayListBuilder* aBu
return item;
}
/**
* Check if a frame should be visited for building display list.
*/
static bool
DescendIntoChild(nsDisplayListBuilder* aBuilder, nsIFrame *aChild,
- const nsRect& aDirty)
+ const nsRect& aVisible, const nsRect& aDirty)
{
nsIFrame* child = aChild;
const nsRect& dirty = aDirty;
if (!(child->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
// No need to descend into child to catch placeholders for visible
// positioned stuff. So see if we can short-circuit frame traversal here.
@@ -2933,17 +2941,21 @@ DescendIntoChild(nsDisplayListBuilder* a
// There are cases where the "ignore scroll frame" on the builder is not set
// correctly, and so we additionally want to catch cases where the child is
// a root scrollframe and we are ignoring scrolling on the viewport.
nsIPresShell* shell = child->PresContext()->PresShell();
bool keepDescending = child == aBuilder->GetIgnoreScrollFrame() ||
(shell->IgnoringViewportScrolling() && child == shell->GetRootScrollFrame());
if (!keepDescending) {
nsRect childDirty;
- if (!childDirty.IntersectRect(dirty, child->GetVisualOverflowRect())) {
+ if (!childDirty.IntersectRect(dirty, child->GetVisualOverflowRect()) &&
+ (!child->ForceDescendIntoIfVisible())) {
+ return false;
+ }
+ if (!childDirty.IntersectRect(aVisible, child->GetVisualOverflowRect())) {
return false;
}
// Usually we could set dirty to childDirty now but there's no
// benefit, and it can be confusing. It can especially confuse
// situations where we're going to ignore a scrollframe's clipping;
// we wouldn't want to clip the dirty area to the scrollframe's
// bounds in that case.
}
@@ -2985,23 +2997,24 @@ nsIFrame::BuildDisplayListForChild(nsDis
// path, the most common one of THE COMMON CASE mentioned later.
MOZ_ASSERT(child->Type() != LayoutFrameType::Placeholder);
MOZ_ASSERT(!aBuilder->GetSelectedFramesOnly() &&
!aBuilder->GetIncludeAllOutOfFlows(),
"It should be held for painting to window");
// dirty rect in child-relative coordinates
nsRect dirty = aBuilder->GetDirtyRect() - child->GetOffsetTo(this);
-
- if (!DescendIntoChild(aBuilder, child, dirty)) {
+ nsRect visible = aBuilder->GetVisibleRect() - child->GetOffsetTo(this);
+
+ if (!DescendIntoChild(aBuilder, child, visible, dirty)) {
return;
}
nsDisplayListBuilder::AutoBuildingDisplayList
- buildingForChild(aBuilder, child, dirty, false);
+ buildingForChild(aBuilder, child, visible, dirty, false);
CheckForApzAwareEventHandlers(aBuilder, child);
nsDisplayLayerEventRegions* eventRegions = aBuilder->GetLayerEventRegions();
if (eventRegions) {
eventRegions->AddFrame(aBuilder, child);
}
@@ -3034,16 +3047,17 @@ nsIFrame::BuildDisplayListForChild(nsDis
// pseudo-stacking-context.
pseudoStackingContext = true;
awayFromCommonPath = true;
}
// dirty rect in child-relative coordinates
NS_ASSERTION(aBuilder->GetCurrentFrame() == this, "Wrong coord space!");
nsPoint offset = child->GetOffsetTo(this);
+ nsRect visible = aBuilder->GetVisibleRect() - offset;
nsRect dirty = aBuilder->GetDirtyRect() - offset;
nsDisplayListBuilder::OutOfFlowDisplayData* savedOutOfFlowData = nullptr;
bool isPlaceholder = false;
if (child->IsPlaceholderFrame()) {
isPlaceholder = true;
nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(child);
child = placeholder->GetOutOfFlowFrame();
@@ -3063,40 +3077,43 @@ nsIFrame::BuildDisplayListForChild(nsDis
if (placeholder->GetStateBits() & PLACEHOLDER_FOR_TOPLAYER) {
return;
}
// Recheck NS_FRAME_TOO_DEEP_IN_FRAME_TREE
if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
return;
savedOutOfFlowData = nsDisplayListBuilder::GetOutOfFlowData(child);
if (savedOutOfFlowData) {
+ visible = savedOutOfFlowData->mVisibleRect;
dirty = savedOutOfFlowData->mDirtyRect;
} else {
// The out-of-flow frame did not intersect the dirty area. We may still
// need to traverse into it, since it may contain placeholders we need
// to enter to reach other out-of-flow frames that are visible.
+ visible.SetEmpty();
dirty.SetEmpty();
}
pseudoStackingContext = true;
awayFromCommonPath = true;
}
NS_ASSERTION(!child->IsPlaceholderFrame(),
"Should have dealt with placeholders already");
if (aBuilder->GetSelectedFramesOnly() &&
child->IsLeaf() &&
!aChild->IsSelected()) {
return;
}
if (aBuilder->GetIncludeAllOutOfFlows() &&
(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
+ visible = child->GetVisualOverflowRect();
dirty = child->GetVisualOverflowRect();
awayFromCommonPath = true;
- } else if (!DescendIntoChild(aBuilder, child, dirty)) {
+ } else if (!DescendIntoChild(aBuilder, child, visible, dirty)) {
return;
}
// XXX need to have inline-block and inline-table set pseudoStackingContext
const nsStyleDisplay* ourDisp = StyleDisplay();
// REVIEW: Taken from nsBoxFrame::Paint
// Don't paint our children if the theme object is a leaf.
@@ -3132,32 +3149,32 @@ nsIFrame::BuildDisplayListForChild(nsDis
// If you change this, also change IsPseudoStackingContextFromStyle()
pseudoStackingContext = true;
awayFromCommonPath = true;
}
NS_ASSERTION(!isStackingContext || pseudoStackingContext,
"Stacking contexts must also be pseudo-stacking-contexts");
nsDisplayListBuilder::AutoBuildingDisplayList
- buildingForChild(aBuilder, child, dirty, pseudoStackingContext);
+ buildingForChild(aBuilder, child, visible, dirty, pseudoStackingContext);
DisplayListClipState::AutoClipMultiple clipState(aBuilder);
nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
CheckForApzAwareEventHandlers(aBuilder, child);
if (savedOutOfFlowData) {
aBuilder->SetBuildingInvisibleItems(false);
clipState.SetClipChainForContainingBlockDescendants(
savedOutOfFlowData->mContainingBlockClipChain);
asrSetter.SetCurrentActiveScrolledRoot(
savedOutOfFlowData->mContainingBlockActiveScrolledRoot);
MOZ_ASSERT(awayFromCommonPath, "It is impossible when savedOutOfFlowData is true");
} else if (GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO &&
isPlaceholder) {
- NS_ASSERTION(dirty.IsEmpty(), "should have empty visible rect");
+ NS_ASSERTION(visible.IsEmpty(), "should have empty visible 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
@@ -3194,16 +3211,17 @@ nsIFrame::BuildDisplayListForChild(nsDis
nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
child->BuildDisplayListForStackingContext(aBuilder, &list);
wrapListASR = contASRTracker.GetContainerASR();
aBuilder->DisplayCaret(child, &list);
} else {
Maybe<nsRect> clipPropClip =
child->GetClipPropClipRect(disp, effects, child->GetSize());
if (clipPropClip) {
+ aBuilder->IntersectVisibleRect(*clipPropClip);
aBuilder->IntersectDirtyRect(*clipPropClip);
clipState.ClipContentDescendants(
*clipPropClip + aBuilder->ToReferenceFrame(child));
awayFromCommonPath = true;
}
child->MarkAbsoluteFramesForDisplayList(aBuilder);
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3122,31 +3122,34 @@ ScrollFrameHelper::AppendScrollPartsTo(n
flags |= nsDisplayOwnLayer::HORIZONTAL_SCROLLBAR;
appendToTopFlags |= APPEND_SCROLLBAR_CONTAINER;
}
// The display port doesn't necessarily include the scrollbars, so just
// include all of the scrollbars if we are in a RCD-RSF. We only do
// this for the root scrollframe of the root content document, which is
// zoomable, and where the scrollbar sizes are bounded by the widget.
+ nsRect visible = mIsRoot && mOuter->PresContext()->IsRootContentDocument()
+ ? scrollParts[i]->GetVisualOverflowRectRelativeToParent()
+ : aBuilder->GetVisibleRect();
nsRect dirty = mIsRoot && mOuter->PresContext()->IsRootContentDocument()
? scrollParts[i]->GetVisualOverflowRectRelativeToParent()
: aBuilder->GetDirtyRect();
// Always create layers for overlay scrollbars so that we don't create a
// giant layer covering the whole scrollport if both scrollbars are visible.
bool isOverlayScrollbar = (flags != 0) && overlayScrollbars;
bool createLayer = aCreateLayer || isOverlayScrollbar ||
gfxPrefs::AlwaysLayerizeScrollbarTrackTestOnly();
nsDisplayListCollection partList(aBuilder);
{
nsDisplayListBuilder::AutoBuildingDisplayList
buildingForChild(aBuilder, mOuter,
- dirty, true);
+ visible, dirty, true);
nsDisplayListBuilder::AutoCurrentScrollbarInfoSetter
infoSetter(aBuilder, scrollTargetId, flags, createLayer);
mOuter->BuildDisplayListForChild(
aBuilder, scrollParts[i], partList,
nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
}
@@ -3155,16 +3158,17 @@ ScrollFrameHelper::AppendScrollPartsTo(n
}
if (aPositioned) {
appendToTopFlags |= APPEND_POSITIONED;
}
{
nsDisplayListBuilder::AutoBuildingDisplayList
buildingForChild(aBuilder, scrollParts[i],
+ visible + mOuter->GetOffsetTo(scrollParts[i]),
dirty + mOuter->GetOffsetTo(scrollParts[i]), true);
nsDisplayListBuilder::AutoCurrentScrollbarInfoSetter
infoSetter(aBuilder, scrollTargetId, flags, createLayer);
// DISPLAY_CHILD_FORCE_STACKING_CONTEXT put everything into
// partList.PositionedDescendants().
::AppendToTop(aBuilder, aLists,
partList.PositionedDescendants(), scrollParts[i],
appendToTopFlags);
@@ -3304,30 +3308,34 @@ ScrollFrameHelper::BuildDisplayList(nsDi
// Overflow clipping can never clip frames outside our subtree, so there
// is no need to worry about whether we are a moving frame that might clip
// non-moving frames.
// Not all our descendants will be clipped by overflow clipping, but all
// the ones that aren't clipped will be out of flow frames that have already
// had dirty rects saved for them by their parent frames calling
// MarkOutOfFlowChildrenForDisplayList, so it's safe to restrict our
// dirty rect here.
+ nsRect visibleRect = aBuilder->GetVisibleRect();
nsRect dirtyRect = aBuilder->GetDirtyRect();
if (!ignoringThisScrollFrame) {
+ visibleRect = visibleRect.Intersect(mScrollPort);
dirtyRect = dirtyRect.Intersect(mScrollPort);
}
- Unused << DecideScrollableLayer(aBuilder, &dirtyRect,
+ bool usingDisplayPortInvalidRect = false;
+ Unused << DecideScrollableLayer(aBuilder, &visibleRect, &dirtyRect,
/* aSetBase = */ !mIsRoot);
if (aBuilder->IsForFrameVisibility()) {
// We expand the dirty rect to catch frames just outside of the scroll port.
// We use the dirty rect instead of the whole scroll port to prevent
// too much expansion in the presence of very large (bigger than the
// viewport) scroll ports.
dirtyRect = ExpandRectToNearlyVisible(dirtyRect);
+ visibleRect = dirtyRect;
}
// We put non-overlay scrollbars in their own layers when this is the root
// scroll frame and we are a toplevel content document. In this situation,
// the scrollbar(s) would normally be assigned their own layer anyway, since
// they're not scrolled with the rest of the document. But when both
// scrollbars are visible, the layer's visible rectangle would be the size
// of the viewport, so most layer implementations would create a layer buffer
@@ -3358,17 +3366,17 @@ ScrollFrameHelper::BuildDisplayList(nsDi
nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
if (aBuilder->IsPaintingToWindow() &&
gfxPrefs::LayoutUseContainersForRootFrames() && mIsRoot) {
asrSetter.EnterScrollFrame(sf);
aBuilder->SetActiveScrolledRootForRootScrollframe(aBuilder->CurrentActiveScrolledRoot());
}
nsDisplayListBuilder::AutoBuildingDisplayList
- building(aBuilder, mOuter, dirtyRect, aBuilder->IsAtRootOfPseudoStackingContext());
+ building(aBuilder, mOuter, visibleRect, dirtyRect, aBuilder->IsAtRootOfPseudoStackingContext());
// Don't clip the scrolled child, and don't paint scrollbars/scrollcorner.
// The scrolled frame shouldn't have its own background/border, so we
// can just pass aLists directly.
mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, aLists);
}
if (addScrollBars) {
@@ -3533,23 +3541,23 @@ ScrollFrameHelper::BuildDisplayList(nsDi
// whole display port up until that fractional edge, and there is a
// transparent display item that overlaps the edge. We want to prevent
// this transparent item from enlarging the scrolled layer's visible
// region beyond its opaque region. The dirty rect doesn't do that -
// it gets rounded out, whereas a true clip gets rounded to nearest
// pixels.
// If there is no display port, we don't need this because the clip
// from the scroll port is still applied.
- scrolledRectClip = scrolledRectClip.Intersect(dirtyRect);
+ scrolledRectClip = scrolledRectClip.Intersect(visibleRect);
}
scrolledRectClipState.ClipContainingBlockDescendants(
scrolledRectClip + aBuilder->ToReferenceFrame(mOuter));
nsDisplayListBuilder::AutoBuildingDisplayList
- building(aBuilder, mOuter, dirtyRect, aBuilder->IsAtRootOfPseudoStackingContext());
+ building(aBuilder, mOuter, visibleRect, dirtyRect, aBuilder->IsAtRootOfPseudoStackingContext());
mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, scrolledContent);
}
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
@@ -3578,17 +3586,18 @@ ScrollFrameHelper::BuildDisplayList(nsDi
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,
+ nsRect copyOfVisibleRect = visibleRect;
+ Unused << DecideScrollableLayer(aBuilder, ©OfVisibleRect, ©OfDirtyRect,
/* aSetBase = */ false);
if (mWillBuildScrollableLayer) {
asrSetter.InsertScrollFrame(sf);
}
}
}
}
@@ -3623,36 +3632,37 @@ ScrollFrameHelper::BuildDisplayList(nsDi
// Now display overlay scrollbars and the resizer, if we have one.
AppendScrollPartsTo(aBuilder, scrolledContent, createLayersForScrollbars, true);
scrolledContent.MoveTo(aLists);
}
bool
ScrollFrameHelper::DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
+ nsRect* aVisibleRect,
nsRect* aDirtyRect,
bool aSetBase)
{
// Save and check if this changes so we can recompute the current agr.
bool oldWillBuildScrollableLayer = mWillBuildScrollableLayer;
nsIContent* content = mOuter->GetContent();
bool usingDisplayPort = nsLayoutUtils::HasDisplayPort(content);
if (aBuilder->IsPaintingToWindow()) {
if (aSetBase) {
- nsRect displayportBase = *aDirtyRect;
+ nsRect displayportBase = *aVisibleRect;
nsPresContext* pc = mOuter->PresContext();
if (mIsRoot && (pc->IsRootContentDocument() || !pc->GetParentPresContext())) {
displayportBase =
nsRect(nsPoint(0, 0), nsLayoutUtils::CalculateCompositionSizeForFrame(mOuter));
} else {
- // Make the displayport base equal to the dirty rect restricted to
+ // Make the displayport base equal to the visible rect restricted to
// the scrollport and the root composition bounds, relative to the
// scrollport.
- displayportBase = aDirtyRect->Intersect(mScrollPort);
+ displayportBase = aVisibleRect->Intersect(mScrollPort);
// Only restrict to the root composition bounds if necessary,
// as the required coordinate transformation is expensive.
if (usingDisplayPort) {
const nsPresContext* rootPresContext =
pc->GetToplevelContentDocumentPresContext();
if (!rootPresContext) {
rootPresContext = pc->GetRootPresContext();
@@ -3729,22 +3739,25 @@ ScrollFrameHelper::DecideScrollableLayer
// displayport base.
MOZ_ASSERT(content->GetProperty(nsGkAtoms::DisplayPortBase));
nsRect displayPort;
usingDisplayPort =
nsLayoutUtils::GetDisplayPort(content, &displayPort, RelativeTo::ScrollFrame);
if (usingDisplayPort) {
// Override the dirty rectangle if the displayport has been set.
+ *aVisibleRect = displayPort;
*aDirtyRect = displayPort;
} else if (mIsRoot) {
// The displayPort getter takes care of adjusting for resolution. So if
// we have resolution but no displayPort then we need to adjust for
// resolution here.
nsIPresShell* presShell = mOuter->PresContext()->PresShell();
+ *aVisibleRect = aVisibleRect->RemoveResolution(
+ presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f);
*aDirtyRect = aDirtyRect->RemoveResolution(
presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f);
}
}
// Since making new layers is expensive, only create a scrollable layer
// for some scroll frames.
// When a displayport is being used, force building of a layer so that
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -409,16 +409,17 @@ public:
void SetScrollableByAPZ(bool aScrollable);
void SetZoomableByAPZ(bool aZoomable);
bool UsesContainerScrolling() const;
ScrollSnapInfo GetScrollSnapInfo() const;
bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
+ nsRect* aVisibleRect,
nsRect* aDirtyRect,
bool aSetBase);
void NotifyApproximateFrameVisibilityUpdate(bool aIgnoreDisplayPort);
bool GetDisplayPortAtLastApproximateFrameVisibilityUpdate(nsRect* aDisplayPort);
bool AllowDisplayPortExpiration();
void TriggerDisplayPortExpiration();
void ResetDisplayPortExpiryTimer();
@@ -953,19 +954,20 @@ public:
}
virtual void MarkScrollbarsDirtyForReflow() const override {
mHelper.MarkScrollbarsDirtyForReflow();
}
virtual bool UsesContainerScrolling() const override {
return mHelper.UsesContainerScrolling();
}
virtual bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
+ nsRect* aVisibleRect,
nsRect* aDirtyRect,
bool aSetBase) override {
- return mHelper.DecideScrollableLayer(aBuilder, aDirtyRect, aSetBase);
+ return mHelper.DecideScrollableLayer(aBuilder, aVisibleRect, aDirtyRect, aSetBase);
}
virtual void NotifyApproximateFrameVisibilityUpdate(bool aIgnoreDisplayPort) override {
mHelper.NotifyApproximateFrameVisibilityUpdate(aIgnoreDisplayPort);
}
virtual bool GetDisplayPortAtLastApproximateFrameVisibilityUpdate(nsRect* aDisplayPort) override {
return mHelper.GetDisplayPortAtLastApproximateFrameVisibilityUpdate(aDisplayPort);
}
void TriggerDisplayPortExpiration() override {
@@ -1468,19 +1470,20 @@ public:
}
void SetScrollableByAPZ(bool aScrollable) override {
mHelper.SetScrollableByAPZ(aScrollable);
}
void SetZoomableByAPZ(bool aZoomable) override {
mHelper.SetZoomableByAPZ(aZoomable);
}
virtual bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
+ nsRect* aVisibleRect,
nsRect* aDirtyRect,
bool aSetBase) override {
- return mHelper.DecideScrollableLayer(aBuilder, aDirtyRect, aSetBase);
+ return mHelper.DecideScrollableLayer(aBuilder, aVisibleRect, aDirtyRect, aSetBase);
}
virtual void NotifyApproximateFrameVisibilityUpdate(bool aIgnoreDisplayPort) override {
mHelper.NotifyApproximateFrameVisibilityUpdate(aIgnoreDisplayPort);
}
virtual bool GetDisplayPortAtLastApproximateFrameVisibilityUpdate(nsRect* aDisplayPort) override {
return mHelper.GetDisplayPortAtLastApproximateFrameVisibilityUpdate(aDisplayPort);
}
void TriggerDisplayPortExpiration() override {
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -618,16 +618,17 @@ public:
, mState(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY)
, mClass(aID)
, mMayHaveRoundedCorners(false)
, mHasImageRequest(false)
, mHasFirstLetterChild(false)
, mParentIsWrapperAnonBox(false)
, mIsWrapperBoxNeedingRestyle(false)
, mReflowRequestedForCharDataChange(false)
+ , mForceDescendIntoIfVisible(false)
, mIsPrimaryFrame(false)
{
mozilla::PodZero(&mOverflow);
}
nsPresContext* PresContext() const {
return StyleContext()->PresContext();
}
@@ -4071,16 +4072,19 @@ public:
nscoord aBoxSizingToMarginEdge,
const nsStyleCoord& aCoord,
ComputeSizeFlags aFlags = eDefault);
DisplayItemArray& DisplayItemData() { return mDisplayItemData; }
void DestroyAnonymousContent(already_AddRefed<nsIContent> aContent);
+ bool ForceDescendIntoIfVisible() { return mForceDescendIntoIfVisible; }
+ void SetForceDescendIntoIfVisible(bool aForce) { mForceDescendIntoIfVisible = aForce; }
+
protected:
/**
* Reparent this frame's view if it has one.
*/
void ReparentFrameViewTo(nsViewManager* aViewManager,
nsView* aNewParentView,
nsView* aOldParentView);
@@ -4231,25 +4235,32 @@ protected:
* available in a gap. If bits become more scarce, we should perhaps consider
* expanding the range of frame-specific state bits in nsFrameStateBits.h and
* moving this to be one of those (e.g. by swapping one of the adjacent
* general-purpose bits to take the place of this bool:1 here, so we can grow
* that range of frame-specific bits by 1).
*/
bool mReflowRequestedForCharDataChange : 1;
+ /**
+ * This bit is used during BuildDisplayList to mark frames that need to
+ * have display items rebuilt. We will descend into them if they are
+ * currently visible, even if they don't intersect the dirty area.
+ */
+ bool mForceDescendIntoIfVisible : 1;
+
private:
/**
* True if this is the primary frame for mContent.
*/
bool mIsPrimaryFrame : 1;
protected:
- // There is a 9-bit gap left here.
+ // There is a 8-bit gap left here.
// Helpers
/**
* Can we stop inside this frame when we're skipping non-rendered whitespace?
* @param aForward [in] Are we moving forward (or backward) in content order.
* @param aOffset [in/out] At what offset into the frame to start looking.
* on output - what offset was reached (whether or not we found a place to stop).
* @return STOP: An appropriate offset was found within this frame,
--- a/layout/generic/nsIScrollableFrame.h
+++ b/layout/generic/nsIScrollableFrame.h
@@ -447,23 +447,26 @@ public:
/**
* Whether or not this frame uses containerful scrolling.
*/
virtual bool UsesContainerScrolling() const = 0;
/**
* Determine if we should build a scrollable layer for this scroll frame and
* return the result. It will also record this result on the scroll frame.
+ * Pass the visible rect in aVisibleRect. On return it will be set to the
+ * displayport if there is one.
* Pass the dirty rect in aDirtyRect. On return it will be set to the
- * displayport if there is one (ie the dirty rect that should be used).
+ * dirty rect inside the displayport (ie the dirty rect that should be used).
* This function will set the display port base rect if aSetBase is true.
* aSetBase is only allowed to be false if there has been a call with it
* set to true before on the same paint.
*/
virtual bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
+ nsRect* aVisibleRect,
nsRect* aDirtyRect,
bool aSetBase) = 0;
/**
* Notification that this scroll frame is getting its frame visibility updated.
* aIgnoreDisplayPort indicates that the display port was ignored (because
* there was no suitable base rect)
*/
--- a/layout/generic/nsPageFrame.cpp
+++ b/layout/generic/nsPageFrame.cpp
@@ -541,44 +541,44 @@ nsPageFrame::BuildDisplayList(nsDisplayL
{
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
// Overwrite current clip, since we're going to wrap in a transform
// and the current clip is no longer meaningful.
clipState.Clear();
clipState.ClipContainingBlockDescendants(clipRect, nullptr);
- nsRect dirtyRect = child->GetVisualOverflowRectRelativeToSelf();
+ nsRect visibleRect = child->GetVisualOverflowRectRelativeToSelf();
nsDisplayListBuilder::AutoBuildingDisplayList
- buildingForChild(aBuilder, child, dirtyRect,
+ buildingForChild(aBuilder, child, visibleRect, visibleRect,
aBuilder->IsAtRootOfPseudoStackingContext());
child->BuildDisplayListForStackingContext(aBuilder, &content);
// We may need to paint out-of-flow frames whose placeholders are
// on other pages. Add those pages to our display list. Note that
// out-of-flow frames can't be placed after their placeholders so
// we don't have to process earlier pages. The display lists for
// these extra pages are pruned so that only display items for the
// page we currently care about (which we would have reached by
// following placeholders to their out-of-flows) end up on the list.
nsIFrame* page = child;
while ((page = GetNextPage(page)) != nullptr) {
- nsRect childDirty = dirtyRect + child->GetOffsetTo(page);
+ nsRect childVisible = visibleRect + child->GetOffsetTo(page);
nsDisplayListBuilder::AutoBuildingDisplayList
- buildingForChild(aBuilder, page, childDirty,
+ buildingForChild(aBuilder, page, childVisible, childVisible,
aBuilder->IsAtRootOfPseudoStackingContext());
BuildDisplayListForExtraPage(aBuilder, this, page, &content);
}
- // Invoke AutoBuildingDisplayList to ensure that the correct dirtyRect
+ // Invoke AutoBuildingDisplayList to ensure that the correct visibleRect
// is used to compute the visible rect if AddCanvasBackgroundColorItem
// creates a display item.
nsDisplayListBuilder::AutoBuildingDisplayList
- building(aBuilder, child, dirtyRect, true);
+ building(aBuilder, child, visibleRect, visibleRect, true);
// Add the canvas background color to the bottom of the list. This
// happens after we've built the list so that AddCanvasBackgroundColorItem
// can monkey with the contents if necessary.
nsRect backgroundRect =
nsRect(aBuilder->ToReferenceFrame(child), child->GetSize());
PresContext()->GetPresShell()->AddCanvasBackgroundColorItem(
--- a/layout/generic/nsSimplePageSequenceFrame.cpp
+++ b/layout/generic/nsSimplePageSequenceFrame.cpp
@@ -833,24 +833,25 @@ nsSimplePageSequenceFrame::BuildDisplayL
{
// Clear clip state while we construct the children of the
// nsDisplayTransform, since they'll be in a different coordinate system.
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
clipState.Clear();
nsIFrame* child = PrincipalChildList().FirstChild();
- nsRect dirty = aBuilder->GetDirtyRect();
- dirty.ScaleInverseRoundOut(PresContext()->GetPrintPreviewScale());
+ nsRect visible = aBuilder->GetVisibleRect();
+ visible.ScaleInverseRoundOut(PresContext()->GetPrintPreviewScale());
while (child) {
- if (child->GetVisualOverflowRectRelativeToParent().Intersects(dirty)) {
+ if (child->GetVisualOverflowRectRelativeToParent().Intersects(visible)) {
nsDisplayListBuilder::AutoBuildingDisplayList
buildingForChild(aBuilder, child,
- dirty - child->GetPosition(),
+ visible - child->GetPosition(),
+ visible - child->GetPosition(),
aBuilder->IsAtRootOfPseudoStackingContext());
child->BuildDisplayListForStackingContext(aBuilder, &content);
aBuilder->ResetMarkedFramesForDisplayList();
}
child = child->GetNextSibling();
}
}
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -380,49 +380,54 @@ nsSubDocumentFrame::BuildDisplayList(nsD
nsIFrame* subdocRootFrame = presShell->GetRootFrame();
nsPresContext* presContext = presShell->GetPresContext();
int32_t parentAPD = PresContext()->AppUnitsPerDevPixel();
int32_t subdocAPD = presContext->AppUnitsPerDevPixel();
+ nsRect visible;
nsRect dirty;
bool haveDisplayPort = false;
bool ignoreViewportScrolling = false;
nsIFrame* savedIgnoreScrollFrame = nullptr;
if (subdocRootFrame) {
// get the dirty rect relative to the root frame of the subdoc
+ visible = aBuilder->GetVisibleRect() + GetOffsetToCrossDoc(subdocRootFrame);
dirty = aBuilder->GetDirtyRect() + GetOffsetToCrossDoc(subdocRootFrame);
// and convert into the appunits of the subdoc
+ visible = visible.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
dirty = dirty.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
nsIScrollableFrame* rootScrollableFrame = presShell->GetRootScrollFrameAsScrollable();
MOZ_ASSERT(rootScrollableFrame);
// Use a copy, so the rects don't get modified.
nsRect copyOfDirty = dirty;
+ nsRect copyOfVisible = visible;
haveDisplayPort = rootScrollableFrame->DecideScrollableLayer(aBuilder,
- ©OfDirty,
+ ©OfVisible, ©OfDirty,
/* aSetBase = */ true);
if (!gfxPrefs::LayoutUseContainersForRootFrames() ||
!aBuilder->IsPaintingToWindow()) {
haveDisplayPort = false;
}
ignoreViewportScrolling = presShell->IgnoringViewportScrolling();
if (ignoreViewportScrolling) {
savedIgnoreScrollFrame = aBuilder->GetIgnoreScrollFrame();
aBuilder->SetIgnoreScrollFrame(rootScrollFrame);
}
}
aBuilder->EnterPresShell(subdocRootFrame, pointerEventsNone);
} else {
+ visible = aBuilder->GetVisibleRect();
dirty = aBuilder->GetDirtyRect();
}
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
if (ShouldClipSubdocument()) {
clipState.ClipContainingBlockDescendantsToContentBox(aBuilder, this);
}
@@ -458,17 +463,17 @@ nsSubDocumentFrame::BuildDisplayList(nsD
nestedClipState.Clear();
}
// Invoke AutoBuildingDisplayList to ensure that the correct dirty rect
// is used to compute the visible rect if AddCanvasBackgroundColorItem
// creates a display item.
nsIFrame* frame = subdocRootFrame ? subdocRootFrame : this;
nsDisplayListBuilder::AutoBuildingDisplayList
- building(aBuilder, frame, dirty, true);
+ building(aBuilder, frame, visible, dirty, true);
if (subdocRootFrame) {
nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(
aBuilder,
ignoreViewportScrolling && rootScrollFrame && rootScrollFrame->GetContent()
? nsLayoutUtils::FindOrCreateIDFor(rootScrollFrame->GetContent())
: aBuilder->GetCurrentScrollParentId());
@@ -562,17 +567,17 @@ nsSubDocumentFrame::BuildDisplayList(nsD
!nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) {
nsRect bounds = GetContentRectRelativeToSelf() +
aBuilder->ToReferenceFrame(this);
// Invoke AutoBuildingDisplayList to ensure that the correct dirty rect
// is used to compute the visible rect if AddCanvasBackgroundColorItem
// creates a display item.
nsDisplayListBuilder::AutoBuildingDisplayList
- building(aBuilder, this, dirty, true);
+ building(aBuilder, this, visible, dirty, true);
// Add the canvas background color to the bottom of the list. This
// happens after we've built the list so that AddCanvasBackgroundColorItem
// can monkey with the contents if necessary.
uint32_t flags = nsIPresShell::FORCE_DRAW | nsIPresShell::APPEND_UNSCROLLED_ONLY;
presShell->AddCanvasBackgroundColorItem(
*aBuilder, childItems, this, bounds, NS_RGBA(0,0,0,0), flags);
}
--- a/layout/generic/nsVideoFrame.cpp
+++ b/layout/generic/nsVideoFrame.cpp
@@ -579,16 +579,17 @@ nsVideoFrame::BuildDisplayList(nsDisplay
// but only want to draw mPosterImage conditionally. Others we
// always add to the display list.
for (nsIFrame* child : mFrames) {
if (child->GetContent() != mPosterImage || shouldDisplayPoster ||
child->IsBoxFrame()) {
nsDisplayListBuilder::AutoBuildingDisplayList
buildingForChild(aBuilder, child,
+ aBuilder->GetVisibleRect() - child->GetOffsetTo(this),
aBuilder->GetDirtyRect() - child->GetOffsetTo(this),
aBuilder->IsAtRootOfPseudoStackingContext());
child->BuildDisplayListForStackingContext(aBuilder, aLists.Content());
}
}
}
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -991,29 +991,48 @@ void
nsDisplayListBuilder::EndFrame()
{
mFrameToAnimatedGeometryRootMap.Clear();
mActiveScrolledRoots.Clear();
nsCSSRendering::EndFrameTreesLocked();
}
-static void MarkFrameForDisplay(nsIFrame* aFrame, nsIFrame* aStopAtFrame) {
+void
+nsDisplayListBuilder::MarkFrameForDisplay(nsIFrame* aFrame, nsIFrame* aStopAtFrame)
+{
+ mFramesMarkedForDisplay.AppendElement(aFrame);
for (nsIFrame* f = aFrame; f;
f = nsLayoutUtils::GetParentOrPlaceholderFor(f)) {
if (f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)
return;
f->AddStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
if (f == aStopAtFrame) {
// we've reached a frame that we know will be painted, so we can stop.
break;
}
}
}
+void
+nsDisplayListBuilder::MarkFrameForDisplayIfVisible(nsIFrame* aFrame, nsIFrame* aStopAtFrame)
+{
+ mFramesMarkedForDisplay.AppendElement(aFrame);
+ for (nsIFrame* f = aFrame; f;
+ f = nsLayoutUtils::GetParentOrPlaceholderFor(f)) {
+ if (f->ForceDescendIntoIfVisible())
+ return;
+ f->SetForceDescendIntoIfVisible(true);
+ if (f == aStopAtFrame) {
+ // we've reached a frame that we know will be painted, so we can stop.
+ break;
+ }
+ }
+}
+
bool nsDisplayListBuilder::NeedToForceTransparentSurfaceForItem(nsDisplayItem* aItem)
{
return aItem == mGlassDisplayItem || aItem->ClearsBackground();
}
AnimatedGeometryRoot*
nsDisplayListBuilder::WrapAGRForFrame(nsIFrame* aAnimatedGeometryRoot,
bool aIsAsync,
@@ -1088,16 +1107,17 @@ nsDisplayListBuilder::FindAnimatedGeomet
}
return FindAnimatedGeometryRootFor(aItem->Frame());
}
void nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame,
nsIFrame* aFrame)
{
+ nsRect visible = GetVisibleRect();
nsRect dirtyRectRelativeToDirtyFrame = GetDirtyRect();
if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame) &&
IsPaintingToWindow()) {
NS_ASSERTION(aDirtyFrame == aFrame->GetParent(), "Dirty frame should be viewport frame");
// position: fixed items are reflowed into and only drawn inside the
// viewport, or the scroll position clamping scrollport size, if one is
// set.
nsIPresShell* ps = aFrame->PresContext()->PresShell();
@@ -1105,57 +1125,68 @@ void nsDisplayListBuilder::MarkOutOfFlow
dirtyRectRelativeToDirtyFrame =
nsRect(nsPoint(0, 0), ps->GetScrollPositionClampingScrollPortSize());
#ifdef MOZ_WIDGET_ANDROID
} else {
dirtyRectRelativeToDirtyFrame =
nsRect(nsPoint(0, 0), aDirtyFrame->GetSize());
#endif
}
+ // TODO: We probably don't want visible and dirty to be the same here, figure
+ // out what to do.
+ visible = dirtyRectRelativeToDirtyFrame;
}
nsPoint offset = aFrame->GetOffsetTo(aDirtyFrame);
+ visible -= offset;
nsRect dirty = dirtyRectRelativeToDirtyFrame - offset;
nsRect overflowRect = aFrame->GetVisualOverflowRect();
if (aFrame->IsTransformed() &&
EffectCompositor::HasAnimationsForCompositor(aFrame,
eCSSProperty_transform)) {
/**
* Add a fuzz factor to the overflow rectangle so that elements only just
* out of view are pulled into the display list, so they can be
* prerendered if necessary.
*/
overflowRect.Inflate(nsPresContext::CSSPixelsToAppUnits(32));
}
- if (!dirty.IntersectRect(dirty, overflowRect) &&
- !(aFrame->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
+ visible.IntersectRect(visible, overflowRect);
+ dirty.IntersectRect(dirty, overflowRect);
+
+ if (!(aFrame->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO) &&
+ dirty.IsEmpty() &&
+ (!aFrame->ForceDescendIntoIfVisible() ||
+ visible.IsEmpty())) {
return;
}
// mClipState.GetClipChainForContainingBlockDescendants can return pointers
// to objects on the stack, so we need to clone the chain.
const DisplayItemClipChain* clipChain =
CopyWholeChain(mClipState.GetClipChainForContainingBlockDescendants());
const DisplayItemClipChain* combinedClipChain = mClipState.GetCurrentCombinedClipChain(this);
const ActiveScrolledRoot* asr = mCurrentActiveScrolledRoot;
- OutOfFlowDisplayData* data = new OutOfFlowDisplayData(clipChain, combinedClipChain, asr, dirty);
+ OutOfFlowDisplayData* data = new OutOfFlowDisplayData(clipChain, combinedClipChain, asr, visible, dirty);
aFrame->SetProperty(nsDisplayListBuilder::OutOfFlowDisplayDataProperty(), data);
MarkFrameForDisplay(aFrame, aDirtyFrame);
}
static void UnmarkFrameForDisplay(nsIFrame* aFrame) {
aFrame->DeleteProperty(nsDisplayListBuilder::OutOfFlowDisplayDataProperty());
for (nsIFrame* f = aFrame; f;
f = nsLayoutUtils::GetParentOrPlaceholderFor(f)) {
- if (!(f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO))
+ if (!(f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO) &&
+ !f->ForceDescendIntoIfVisible())
return;
f->RemoveStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
+ f->SetForceDescendIntoIfVisible(false);
}
}
nsDisplayListBuilder::~nsDisplayListBuilder() {
NS_ASSERTION(mFramesMarkedForDisplay.Length() == 0,
"All frames should have been unmarked");
NS_ASSERTION(mPresShellStates.Length() == 0,
@@ -1245,17 +1276,16 @@ nsDisplayListBuilder::EnterPresShell(nsI
state->mInsidePointerEventsNoneDoc = pointerEventsNone;
if (!buildCaret)
return;
RefPtr<nsCaret> caret = state->mPresShell->GetCaret();
state->mCaretFrame = caret->GetPaintGeometry(&state->mCaretRect);
if (state->mCaretFrame) {
- mFramesMarkedForDisplay.AppendElement(state->mCaretFrame);
MarkFrameForDisplay(state->mCaretFrame, nullptr);
}
nsPresContext* pc = aReferenceFrame->PresContext();
nsCOMPtr<nsIDocShell> docShell = pc->GetDocShell();
if (docShell) {
docShell->GetWindowDraggingAllowed(&mWindowDraggingAllowed);
}
@@ -1339,18 +1369,16 @@ nsDisplayListBuilder::MarkFramesForDispl
nsIContent* content = e->GetContent();
if (content && content->IsInNativeAnonymousSubtree() && content->IsElement()) {
auto classList = content->AsElement()->ClassList();
if (classList->Contains(NS_LITERAL_STRING("moz-accessiblecaret"))) {
continue;
}
}
}
-
- mFramesMarkedForDisplay.AppendElement(e);
MarkOutOfFlowFrameForDisplay(aDirtyFrame, e);
}
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 ==
@@ -1359,17 +1387,17 @@ nsDisplayListBuilder::MarkFramesForDispl
MOZ_ASSERT(!CurrentPresShellState()->mFixedBackgroundDisplayData,
"already traversed this presshell's root frame?");
const DisplayItemClipChain* clipChain =
CopyWholeChain(mClipState.GetClipChainForContainingBlockDescendants());
const DisplayItemClipChain* combinedClipChain = mClipState.GetCurrentCombinedClipChain(this);
const ActiveScrolledRoot* asr = mCurrentActiveScrolledRoot;
CurrentPresShellState()->mFixedBackgroundDisplayData.emplace(
- clipChain, combinedClipChain, asr, GetDirtyRect());
+ clipChain, combinedClipChain, asr, GetVisibleRect(), GetDirtyRect());
}
}
/**
* 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.
@@ -1382,17 +1410,16 @@ nsDisplayListBuilder::MarkPreserve3DFram
AutoTArray<nsIFrame::ChildList,4> childListArray;
aDirtyFrame->GetChildLists(&childListArray);
nsIFrame::ChildListArrayIterator lists(childListArray);
for (; !lists.IsDone(); lists.Next()) {
nsFrameList::Enumerator childFrames(lists.CurrentList());
for (; !childFrames.AtEnd(); childFrames.Next()) {
nsIFrame *child = childFrames.get();
if (child->Combines3DTransformWithAncestors()) {
- mFramesMarkedForDisplay.AppendElement(child);
MarkFrameForDisplay(child, aDirtyFrame);
}
}
}
}
void*
nsDisplayListBuilder::Allocate(size_t aSize, DisplayItemType aType)
@@ -2690,22 +2717,23 @@ nsDisplayItem::nsDisplayItem(nsDisplayLi
#endif
{
mReferenceFrame = aBuilder->FindReferenceFrameFor(aFrame, &mToReferenceFrame);
// This can return the wrong result if the item override ShouldFixToViewport(),
// the item needs to set it again in its constructor.
mAnimatedGeometryRoot = aBuilder->FindAnimatedGeometryRootFor(aFrame);
MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(aBuilder->RootReferenceFrame(),
*mAnimatedGeometryRoot), "Bad");
- NS_ASSERTION(aBuilder->GetDirtyRect().width >= 0 ||
- !aBuilder->IsForPainting(), "dirty rect not set");
- // The dirty rect is for mCurrentFrame, so we have to use
+ NS_ASSERTION(aBuilder->GetVisibleRect().width >= 0 ||
+ !aBuilder->IsForPainting(), "visible rect not set");
+
+ // The visible rect is for mCurrentFrame, so we have to use
// mCurrentOffsetToReferenceFrame
- mVisibleRect = aBuilder->GetDirtyRect() +
- aBuilder->GetCurrentFrameOffsetToReferenceFrame();
+ mVisibleRect = aBuilder->GetVisibleRect() +
+ aBuilder->GetCurrentFrameOffsetToReferenceFrame();
}
/* static */ bool
nsDisplayItem::ForceActiveLayers()
{
static bool sForce = false;
static bool sForceCached = false;
@@ -3363,30 +3391,32 @@ nsDisplayBackgroundImage::AppendBackgrou
nsDisplayBackgroundImage::InitData bgData =
nsDisplayBackgroundImage::GetInitData(aBuilder, aFrame, i, bgOriginRect, bg,
LayerizeFixed::DO_NOT_LAYERIZE_FIXED_BACKGROUND_IF_AVOIDING_COMPONENT_ALPHA_LAYERS);
if (bgData.shouldFixToViewport) {
auto* displayData = aBuilder->GetCurrentFixedBackgroundDisplayData();
nsDisplayListBuilder::AutoBuildingDisplayList
- buildingDisplayList(aBuilder, aFrame, aBuilder->GetDirtyRect(), false);
+ buildingDisplayList(aBuilder, aFrame, aBuilder->GetVisibleRect(), 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 visibleRect = displayData->mVisibleRect + aFrame->GetOffsetTo(rootFrame);
+ aBuilder->SetVisibleRect(visibleRect);
nsRect dirtyRect = displayData->mDirtyRect + aFrame->GetOffsetTo(rootFrame);
aBuilder->SetDirtyRect(dirtyRect);
}
}
nsDisplayBackgroundImage* bgItem = nullptr;
{
// The clip is captured by the nsDisplayFixedPosition, so clear the
// clip for the nsDisplayBackgroundImage inside.
@@ -5687,18 +5717,19 @@ nsDisplayWrapList::nsDisplayWrapList(nsD
// will have the correct reference frame set (since nsDisplayTransform
// handles this explictly).
nsDisplayItem *i = mListPtr->GetBottom();
if (i && (!i->GetAbove() || i->GetType() == DisplayItemType::TYPE_TRANSFORM) &&
i->Frame() == mFrame) {
mReferenceFrame = i->ReferenceFrame();
mToReferenceFrame = i->ToReferenceFrame();
}
- mVisibleRect = aBuilder->GetDirtyRect() +
- aBuilder->GetCurrentFrameOffsetToReferenceFrame();
+
+ mVisibleRect = aBuilder->GetVisibleRect() +
+ aBuilder->GetCurrentFrameOffsetToReferenceFrame();
}
nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayItem* aItem)
: nsDisplayItem(aBuilder, aFrame)
, mList(aBuilder)
, mOverrideZIndex(0)
, mHasZIndexOverride(false)
@@ -5715,18 +5746,19 @@ nsDisplayWrapList::nsDisplayWrapList(nsD
return;
}
// See the previous nsDisplayWrapList constructor
if (aItem->Frame() == aFrame) {
mReferenceFrame = aItem->ReferenceFrame();
mToReferenceFrame = aItem->ToReferenceFrame();
}
- mVisibleRect = aBuilder->GetDirtyRect() +
- aBuilder->GetCurrentFrameOffsetToReferenceFrame();
+
+ mVisibleRect = aBuilder->GetVisibleRect() +
+ aBuilder->GetCurrentFrameOffsetToReferenceFrame();
}
nsDisplayWrapList::~nsDisplayWrapList() {
MOZ_COUNT_DTOR(nsDisplayWrapList);
}
void
nsDisplayWrapList::MergeDisplayListFromItem(nsDisplayListBuilder* aBuilder,
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -364,24 +364,26 @@ class nsDisplayListBuilder {
Preserves3DContext()
: mAccumulatedRectLevels(0)
{}
Preserves3DContext(const Preserves3DContext &aOther)
: mAccumulatedTransform()
, mAccumulatedRect()
, mAccumulatedRectLevels(0)
+ , mVisibleRect(aOther.mVisibleRect)
, mDirtyRect(aOther.mDirtyRect) {}
// Accmulate transforms of ancestors on the preserves-3d chain.
Matrix4x4 mAccumulatedTransform;
// Accmulate visible rect of descendants in the preserves-3d context.
nsRect mAccumulatedRect;
// How far this frame is from the root of the current 3d context.
int mAccumulatedRectLevels;
+ nsRect mVisibleRect;
nsRect mDirtyRect;
};
/**
* A frame can be in one of three states of AGR.
* AGR_NO means the frame is not an AGR for now.
* AGR_YES means the frame is an AGR for now.
* AGR_MAYBE means the frame is not an AGR for now, but a transition
@@ -627,18 +629,21 @@ public:
*/
void SetDescendIntoSubdocuments(bool aDescend) { mDescendIntoSubdocuments = aDescend; }
bool GetDescendIntoSubdocuments() { return mDescendIntoSubdocuments; }
/**
* Get dirty rect relative to current frame (the frame that we're calling
* BuildDisplayList on right now).
*/
+ const nsRect& GetVisibleRect() { return mVisibleRect; }
const nsRect& GetDirtyRect() { return mDirtyRect; }
+ void SetVisibleRect(const nsRect& aVisibleRect) { mVisibleRect = aVisibleRect; }
+ void IntersectVisibleRect(const nsRect& aVisibleRect) { mVisibleRect.IntersectRect(mVisibleRect, aVisibleRect); }
void SetDirtyRect(const nsRect& aDirtyRect) { mDirtyRect = aDirtyRect; }
void IntersectDirtyRect(const nsRect& aDirtyRect) { mDirtyRect.IntersectRect(mDirtyRect, aDirtyRect); }
const nsIFrame* GetCurrentFrame() { return mCurrentFrame; }
const nsIFrame* GetCurrentReferenceFrame() { return mCurrentReferenceFrame; }
const nsPoint& GetCurrentFrameOffsetToReferenceFrame() { return mCurrentOffsetToReferenceFrame; }
AnimatedGeometryRoot* GetCurrentAnimatedGeometryRoot() {
return mCurrentAGR;
@@ -795,33 +800,37 @@ public:
* (which is relative to aDirtyFrame). If the frames have placeholders
* that might not be displayed, we mark the placeholders and their ancestors
* to ensure that display list construction descends into them
* anyway. nsDisplayListBuilder will take care of unmarking them when it is
* destroyed.
*/
void MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
const nsFrameList& aFrames);
+ void MarkFrameForDisplay(nsIFrame* aFrame, nsIFrame* aStopAtFrame = nullptr);
+ void MarkFrameForDisplayIfVisible(nsIFrame* aFrame, nsIFrame* aStopAtFrame = nullptr);
+
/**
* Mark all child frames that Preserve3D() as needing display.
* Because these frames include transforms set on their parent, dirty rects
* for intermediate frames may be empty, yet child frames could still be visible.
*/
void MarkPreserve3DFramesForDisplayList(nsIFrame* aDirtyFrame);
const nsTArray<ThemeGeometry>& GetThemeGeometries() { return mThemeGeometries; }
/**
* Returns true if we need to descend into this frame when building
* the display list, even though it doesn't intersect the dirty
* rect, because it may have out-of-flows that do so.
*/
- bool ShouldDescendIntoFrame(nsIFrame* aFrame) const {
+ bool ShouldDescendIntoFrame(nsIFrame* aFrame, bool aVisible) const {
return
(aFrame->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO) ||
+ (aVisible && aFrame->ForceDescendIntoIfVisible()) ||
GetIncludeAllOutOfFlows();
}
/**
* Notifies the builder that a particular themed widget exists
* at the given rectangle within the currently built display list.
* For certain appearance values (currently only NS_THEME_TOOLBAR and
* NS_THEME_WINDOW_TITLEBAR) this gets called during every display list
@@ -928,22 +937,25 @@ public:
* aDirtyRect is relative to aForChild.
*/
class AutoBuildingDisplayList;
friend class AutoBuildingDisplayList;
class AutoBuildingDisplayList {
public:
AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder,
nsIFrame* aForChild,
- const nsRect& aDirtyRect, bool aIsRoot)
+ const nsRect& aVisibleRect,
+ const nsRect& aDirtyRect,
+ bool aIsRoot)
: mBuilder(aBuilder),
mPrevFrame(aBuilder->mCurrentFrame),
mPrevReferenceFrame(aBuilder->mCurrentReferenceFrame),
mPrevLayerEventRegions(aBuilder->mLayerEventRegions),
mPrevOffset(aBuilder->mCurrentOffsetToReferenceFrame),
+ mPrevVisibleRect(aBuilder->mVisibleRect),
mPrevDirtyRect(aBuilder->mDirtyRect),
mPrevAGR(aBuilder->mCurrentAGR),
mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext),
mPrevAncestorHasApzAwareEventHandler(aBuilder->mAncestorHasApzAwareEventHandler),
mPrevBuildingInvisibleItems(aBuilder->mBuildingInvisibleItems)
{
if (aForChild->IsTransformed()) {
aBuilder->mCurrentOffsetToReferenceFrame = nsPoint();
@@ -961,22 +973,20 @@ public:
if (mCurrentAGRState == AGR_YES) {
aBuilder->mCurrentAGR = aBuilder->WrapAGRForFrame(aForChild, isAsync, aBuilder->mCurrentAGR);
}
} else if (aForChild != aBuilder->mCurrentFrame) {
aBuilder->mCurrentAGR = aBuilder->FindAnimatedGeometryRootFor(aForChild);
}
MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(aBuilder->RootReferenceFrame(), *aBuilder->mCurrentAGR));
aBuilder->mCurrentFrame = aForChild;
+ aBuilder->mVisibleRect = aVisibleRect;
aBuilder->mDirtyRect = aDirtyRect;
aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot;
}
- void SetDirtyRect(const nsRect& aRect) {
- mBuilder->mDirtyRect = aRect;
- }
void SetReferenceFrameAndCurrentOffset(const nsIFrame* aFrame, const nsPoint& aOffset) {
mBuilder->mCurrentReferenceFrame = aFrame;
mBuilder->mCurrentOffsetToReferenceFrame = aOffset;
}
bool IsAnimatedGeometryRoot() const {
return mCurrentAGRState == AGR_YES;
}
bool MaybeAnimatedGeometryRoot() const {
@@ -985,29 +995,31 @@ public:
void RestoreBuildingInvisibleItemsValue() {
mBuilder->mBuildingInvisibleItems = mPrevBuildingInvisibleItems;
}
~AutoBuildingDisplayList() {
mBuilder->mCurrentFrame = mPrevFrame;
mBuilder->mCurrentReferenceFrame = mPrevReferenceFrame;
mBuilder->mLayerEventRegions = mPrevLayerEventRegions;
mBuilder->mCurrentOffsetToReferenceFrame = mPrevOffset;
+ mBuilder->mVisibleRect = mPrevVisibleRect;
mBuilder->mDirtyRect = mPrevDirtyRect;
mBuilder->mCurrentAGR = mPrevAGR;
mBuilder->mIsAtRootOfPseudoStackingContext = mPrevIsAtRootOfPseudoStackingContext;
mBuilder->mAncestorHasApzAwareEventHandler = mPrevAncestorHasApzAwareEventHandler;
mBuilder->mBuildingInvisibleItems = mPrevBuildingInvisibleItems;
}
private:
nsDisplayListBuilder* mBuilder;
AGRState mCurrentAGRState;
const nsIFrame* mPrevFrame;
const nsIFrame* mPrevReferenceFrame;
nsDisplayLayerEventRegions* mPrevLayerEventRegions;
nsPoint mPrevOffset;
+ nsRect mPrevVisibleRect;
nsRect mPrevDirtyRect;
RefPtr<AnimatedGeometryRoot> mPrevAGR;
bool mPrevIsAtRootOfPseudoStackingContext;
bool mPrevAncestorHasApzAwareEventHandler;
bool mPrevBuildingInvisibleItems;
};
/**
@@ -1349,25 +1361,28 @@ public:
// Helpers for tables
nsDisplayTableItem* GetCurrentTableItem() { return mCurrentTableItem; }
void SetCurrentTableItem(nsDisplayTableItem* aTableItem) { mCurrentTableItem = aTableItem; }
struct OutOfFlowDisplayData {
OutOfFlowDisplayData(const DisplayItemClipChain* aContainingBlockClipChain,
const DisplayItemClipChain* aCombinedClipChain,
const ActiveScrolledRoot* aContainingBlockActiveScrolledRoot,
+ const nsRect &aVisibleRect,
const nsRect &aDirtyRect)
: mContainingBlockClipChain(aContainingBlockClipChain)
, mCombinedClipChain(aCombinedClipChain)
, mContainingBlockActiveScrolledRoot(aContainingBlockActiveScrolledRoot)
+ , mVisibleRect(aVisibleRect)
, mDirtyRect(aDirtyRect)
{}
const DisplayItemClipChain* mContainingBlockClipChain;
const DisplayItemClipChain* mCombinedClipChain; // only necessary for the special case of top layer
const ActiveScrolledRoot* mContainingBlockActiveScrolledRoot;
+ nsRect mVisibleRect;
nsRect mDirtyRect;
};
NS_DECLARE_FRAME_PROPERTY_DELETABLE(OutOfFlowDisplayDataProperty,
OutOfFlowDisplayData)
static OutOfFlowDisplayData* GetOutOfFlowData(nsIFrame* aFrame)
{
@@ -1496,20 +1511,22 @@ public:
mBuilder->mPreserves3DCtx = mSavedCtx;
}
private:
nsDisplayListBuilder* mBuilder;
Preserves3DContext mSavedCtx;
};
- const nsRect GetPreserves3DRects() const {
+ const nsRect GetPreserves3DRects(nsRect* aOutVisibleRect) const {
+ *aOutVisibleRect = mPreserves3DCtx.mVisibleRect;
return mPreserves3DCtx.mDirtyRect;
}
void SavePreserves3DRects() {
+ mPreserves3DCtx.mVisibleRect = mVisibleRect;
mPreserves3DCtx.mDirtyRect = mDirtyRect;
}
bool IsBuildingInvisibleItems() const { return mBuildingInvisibleItems; }
void SetBuildingInvisibleItems(bool aBuildingInvisibleItems) {
mBuildingInvisibleItems = aBuildingInvisibleItems;
}
@@ -1631,16 +1648,17 @@ private:
nsTHashtable<nsPtrHashKey<nsIFrame> > mWillChangeBudgetSet;
// Area of animated geometry root budget already allocated
uint32_t mUsedAGRBudget;
// Set of frames already counted in budget
nsTHashtable<nsPtrHashKey<nsIFrame> > mAGRBudgetSet;
// Relative to mCurrentFrame.
+ nsRect mVisibleRect;
nsRect mDirtyRect;
nsRegion mWindowExcludeGlassRegion;
nsRegion mWindowOpaqueRegion;
LayoutDeviceIntRegion mWindowDraggingRegion;
LayoutDeviceIntRegion mWindowNoDraggingRegion;
// 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
--- a/layout/tables/nsTableRowGroupFrame.cpp
+++ b/layout/tables/nsTableRowGroupFrame.cpp
@@ -207,24 +207,24 @@ DisplayRows(nsDisplayListBuilder* aBuild
// Don't try to use the row cursor if we have to descend into placeholders;
// we might have rows containing placeholders, where the row's overflow
// area doesn't intersect the dirty rect but we need to descend into the row
// to see out of flows.
// Note that we really want to check ShouldDescendIntoFrame for all
// the rows in |f|, but that's exactly what we're trying to avoid, so we
// approximate it by checking it for |f|: if it's true for any row
// in |f| then it's true for |f| itself.
- nsIFrame* kid = aBuilder->ShouldDescendIntoFrame(f) ?
- nullptr : f->GetFirstRowContaining(aBuilder->GetDirtyRect().y, &overflowAbove);
+ nsIFrame* kid = aBuilder->ShouldDescendIntoFrame(f, true) ?
+ nullptr : f->GetFirstRowContaining(aBuilder->GetVisibleRect().y, &overflowAbove);
if (kid) {
// have a cursor, use it
while (kid) {
- if (kid->GetRect().y - overflowAbove >= aBuilder->GetDirtyRect().YMost() &&
- kid->GetNormalRect().y - overflowAbove >= aBuilder->GetDirtyRect().YMost())
+ if (kid->GetRect().y - overflowAbove >= aBuilder->GetVisibleRect().YMost() &&
+ kid->GetNormalRect().y - overflowAbove >= aBuilder->GetVisibleRect().YMost())
break;
f->BuildDisplayListForChild(aBuilder, kid, aLists);
kid = kid->GetNextSibling();
}
return;
}
// No cursor. Traverse children the hard way and build a cursor while we're at it
--- a/layout/xul/nsRootBoxFrame.cpp
+++ b/layout/xul/nsRootBoxFrame.cpp
@@ -172,17 +172,17 @@ void
nsRootBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists)
{
if (mContent && mContent->GetProperty(nsGkAtoms::DisplayPortMargins)) {
// The XUL document's root element may have displayport margins set in
// ChromeProcessController::InitializeRoot, and we should to supply the
// base rect.
nsRect displayPortBase =
- aBuilder->GetDirtyRect().Intersect(nsRect(nsPoint(0, 0), GetSize()));
+ aBuilder->GetVisibleRect().Intersect(nsRect(nsPoint(0, 0), GetSize()));
nsLayoutUtils::SetDisplayPortBase(mContent, displayPortBase);
}
// root boxes don't need a debug border/outline or a selection overlay...
// They *may* have a background propagated to them, so force creation
// of a background display list element.
DisplayBorderBackgroundOutline(aBuilder, aLists, true);
--- a/layout/xul/nsSliderFrame.cpp
+++ b/layout/xul/nsSliderFrame.cpp
@@ -413,21 +413,21 @@ nsSliderFrame::BuildDisplayListForChildr
nsRect overflow = thumb->GetVisualOverflowRectRelativeToParent();
nsSize refSize = aBuilder->RootReferenceFrame()->GetSize();
gfxSize scale = nsLayoutUtils::GetTransformToAncestorScale(thumb);
if (scale.width != 0 && scale.height != 0) {
refSize.width /= scale.width;
refSize.height /= scale.height;
}
- nsRect dirty = aBuilder->GetDirtyRect().Intersect(thumbRect);
- dirty = nsLayoutUtils::ComputePartialPrerenderArea(aBuilder->GetDirtyRect(), overflow, refSize);
+ nsRect dirty = aBuilder->GetVisibleRect().Intersect(thumbRect);
+ dirty = nsLayoutUtils::ComputePartialPrerenderArea(aBuilder->GetVisibleRect(), overflow, refSize);
nsDisplayListBuilder::AutoBuildingDisplayList
- buildingDisplayList(aBuilder, this, dirty, false);
+ buildingDisplayList(aBuilder, this, dirty, dirty, false);
// Clip the thumb layer to the slider track. This is necessary to ensure
// FrameLayerBuilder is able to merge content before and after the
// scrollframe into the same layer (otherwise it thinks the thumb could
// potentially move anywhere within the existing clip).
DisplayListClipState::AutoSaveRestore thumbClipState(aBuilder);
thumbClipState.ClipContainingBlockDescendants(
GetRectRelativeToSelf() + aBuilder->ToReferenceFrame(this));