--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -4056,38 +4056,49 @@ GetModifiedFrames(nsIFrame* aDisplayRoot
if (rootdoc) {
rootdoc->EnumerateSubDocuments(SubDocEnumCb, &modifiedFrames);
}
return modifiedFrames;
}
+// ComputeRebuildRegion debugging
+// #define CRR_DEBUG 0
+#if CRR_DEBUG
+# define CRR_LOG(...) printf_stderr(__VA_ARGS__)
+#else
+# define CRR_LOG(...)
+#endif
+
static bool
ComputeRebuildRegion(nsDisplayListBuilder& aBuilder,
std::vector<WeakFrame>& aModifiedFrames,
nsIFrame* aDisplayRootFrame,
const nsRect& aRootDirtyRect,
nsRect* aOutDirty,
AnimatedGeometryRoot** aOutModifiedAGR,
nsTArray<nsIFrame*>* aOutFramesWithProps)
{
+ CRR_LOG("Computing rebuild regions for %d frames:\n", aModifiedFrames.size());
for (nsIFrame* f : aModifiedFrames) {
if (!f) {
continue;
}
if (f->HasOverrideDirtyRegion()) {
aOutFramesWithProps->AppendElement(f);
}
// TODO: There is almost certainly a faster way of doing this, probably can be combined with the ancestor
// walk for TransformFrameRectToAncestor.
AnimatedGeometryRoot* agr = aBuilder.FindAnimatedGeometryRootFor(f)->GetAsyncAGR();
+ CRR_LOG("Processing frame %p with agr %p\n", f, agr->mFrame);
+
// Convert the frame's overflow rect into the coordinate space
// of the nearest stacking context that has an existing display item.
// We store the overflow rect on that stacking context so that we build
// all items that intersect that changed frame within the stacking context,
// and then we use MarkFrameForDisplayIfVisible to make sure the stacking
// context itself gets built. We don't need to build items that intersect outside
// of the stacking context, since we know the stacking context item exists in
@@ -4098,16 +4109,17 @@ ComputeRebuildRegion(nsDisplayListBuilde
while (currentFrame != aDisplayRootFrame) {
overflow = nsLayoutUtils::TransformFrameRectToAncestor(currentFrame, overflow, aDisplayRootFrame,
nullptr, nullptr,
/* aStopAtStackingContextAndDisplayPort = */ true,
¤tFrame);
MOZ_ASSERT(currentFrame);
if (nsLayoutUtils::FrameHasDisplayPort(currentFrame)) {
+ CRR_LOG("Frame belongs to displayport frame %p\n", currentFrame);
nsIScrollableFrame* sf = do_QueryFrame(currentFrame);
MOZ_ASSERT(sf);
nsRect displayPort;
DebugOnly<bool> hasDisplayPort =
nsLayoutUtils::GetDisplayPort(currentFrame->GetContent(), &displayPort, RelativeTo::ScrollPort);
MOZ_ASSERT(hasDisplayPort);
// get it relative to the scrollport (from the scrollframe)
nsRect r = overflow - sf->GetScrollPortRect().TopLeft();
@@ -4117,29 +4129,31 @@ ComputeRebuildRegion(nsDisplayListBuilde
currentFrame->GetProperty(nsDisplayListBuilder::DisplayListBuildingDisplayPortRect());
if (!rect) {
rect = new nsRect();
currentFrame->SetProperty(nsDisplayListBuilder::DisplayListBuildingDisplayPortRect(), rect);
currentFrame->SetHasOverrideDirtyRegion(true);
}
rect->UnionRect(*rect, r);
aOutFramesWithProps->AppendElement(currentFrame);
+ CRR_LOG("Adding area to displayport draw area: %d %d %d %d\n", r.x, r.y, r.width, r.height);
// TODO: Can we just use MarkFrameForDisplayIfVisible, plus MarkFramesForDifferentAGR to
// ensure that this displayport, plus any items that move relative to it get rebuilt,
// and then not contribute to the root dirty area?
overflow = sf->GetScrollPortRect();
} else {
// Don't contribute to the root dirty area at all.
overflow.SetEmpty();
break;
}
}
if (currentFrame->IsStackingContext()) {
+ CRR_LOG("Frame belongs to stacking context frame %p\n", currentFrame);
// If we found an intermediate stacking context with an existing display item
// then we can store the dirty rect there and stop.
if (currentFrame != aDisplayRootFrame &&
currentFrame->RealDisplayItemData().Length() != 0) {
aBuilder.MarkFrameForDisplayIfVisible(currentFrame);
// Store the stacking context relative dirty area such
// that display list building will pick it up when it
@@ -4148,38 +4162,42 @@ ComputeRebuildRegion(nsDisplayListBuilde
currentFrame->GetProperty(nsDisplayListBuilder::DisplayListBuildingRect());
if (!data) {
data = new nsDisplayListBuilder::DisplayListBuildingData;
currentFrame->SetProperty(nsDisplayListBuilder::DisplayListBuildingRect(), data);
currentFrame->SetHasOverrideDirtyRegion(true);
aOutFramesWithProps->AppendElement(currentFrame);
}
data->mDirtyRect.UnionRect(data->mDirtyRect, overflow);
+ CRR_LOG("Adding area to stacking context draw area: %d %d %d %d\n", overflow.x, overflow.y, overflow.width, overflow.height);
if (!data->mModifiedAGR) {
data->mModifiedAGR = agr;
} else if (data->mModifiedAGR != agr) {
data->mDirtyRect = currentFrame->GetVisualOverflowRectRelativeToSelf();
+ CRR_LOG("Found multiple modified AGRs within this stacking context, giving up\n");
}
// Don't contribute to the root dirty area at all.
agr = nullptr;
overflow.SetEmpty();
break;
}
}
}
aOutDirty->UnionRect(*aOutDirty, overflow);
+ CRR_LOG("Adding area to root draw area: %d %d %d %d\n", overflow.x, overflow.y, overflow.width, overflow.height);
// If we get changed frames from multiple AGRS, then just give up as it gets really complex to
// track which items would need to be marked in MarkFramesForDifferentAGR.
// TODO: We should store the modifiedAGR on the per-stacking context data and only do the
// marking within the scope of the current stacking context.
if (!*aOutModifiedAGR) {
*aOutModifiedAGR = agr;
} else if (agr && *aOutModifiedAGR != agr) {
+ CRR_LOG("Found multiple AGRs in root stacking context, giving up\n");
return false;
}
}
return true;
}
void MarkFramesWithItemsAndImagesModified(nsDisplayList* aList)