Bug 1404181 - Part 16: Track window dragging area contributions per-frame so that can remove contributions from invalidated frames. r?mstange
MozReview-Commit-ID: 5bFYV4wSZa
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -1798,45 +1798,117 @@ nsDisplayListBuilder::AdjustWindowDraggi
// The most important case we need to handle is the scrolled-off tab:
// If the tab bar overflows, tab parts that are clipped by the scrollbox
// 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);
+ nsRect borderBox = aFrame->GetRectRelativeToSelf().Intersect(mVisibleRect);
borderBox += ToReferenceFrame(aFrame);
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)) {
- if (styleUI->mWindowDragging == StyleWindowDragging::Drag) {
- mWindowDraggingRegion.OrWith(transformedDevPixelBorderBoxInt);
- } else {
- mWindowNoDraggingRegion.OrWith(transformedDevPixelBorderBoxInt);
- }
- }
+ if (borderBox.IsEmpty()) {
+ return;
+ }
+
+ LayoutDeviceRect devPixelBorderBox =
+ LayoutDevicePixel::FromAppUnits(borderBox, aFrame->PresContext()->AppUnitsPerDevPixel());
+
+ LayoutDeviceRect transformedDevPixelBorderBox =
+ TransformBy(referenceFrameToRootReferenceFrame, devPixelBorderBox);
+ transformedDevPixelBorderBox.Round();
+ LayoutDeviceIntRect transformedDevPixelBorderBoxInt;
+
+ if (!transformedDevPixelBorderBox.ToIntRect(&transformedDevPixelBorderBoxInt)) {
+ return;
+ }
+
+ LayoutDeviceIntRegion& region =
+ styleUI->mWindowDragging == StyleWindowDragging::Drag
+ ? mWindowDraggingRegion : mWindowNoDraggingRegion;
+
+ if (!IsRetainingDisplayList()) {
+ region.OrWith(transformedDevPixelBorderBoxInt);
+ return;
+ }
+
+ if (styleUI->mWindowDragging == StyleWindowDragging::Drag) {
+ mWindowDraggingFrames.emplace_back(aFrame);
+ mWindowDraggingRects.AppendElement(
+ nsRegion::RectToBox(transformedDevPixelBorderBoxInt.ToUnknownRect()));
+ } else {
+ mWindowNoDraggingFrames.emplace_back(aFrame);
+ mWindowNoDraggingRects.AppendElement(
+ nsRegion::RectToBox(transformedDevPixelBorderBoxInt.ToUnknownRect()));
}
}
LayoutDeviceIntRegion
nsDisplayListBuilder::GetWindowDraggingRegion() const
{
LayoutDeviceIntRegion result;
- result.Sub(mWindowDraggingRegion, mWindowNoDraggingRegion);;
+ if (!IsRetainingDisplayList()) {
+ result.Sub(mWindowDraggingRegion, mWindowNoDraggingRegion);
+ return result;
+ }
+
+ LayoutDeviceIntRegion dragRegion((mozilla::gfx::ArrayView<pixman_box32_t>(mWindowDraggingRects)));
+ LayoutDeviceIntRegion noDragRegion((mozilla::gfx::ArrayView<pixman_box32_t>(mWindowNoDraggingRects)));
+
+ result.Sub(dragRegion, noDragRegion);
return result;
}
+void
+nsDisplayListBuilder::RemoveModifiedWindowDraggingRegion()
+{
+ uint32_t i = 0;
+ uint32_t length = mWindowDraggingFrames.size();
+ while (i < length) {
+ if (!mWindowDraggingFrames[i].IsAlive() ||
+ mWindowDraggingFrames[i]->IsFrameModified()) {
+ // Swap the modified frame to the end of the vector so that
+ // we can remove them all at the end in one go.
+ mWindowDraggingFrames[i] = mWindowDraggingFrames[length - 1];
+ mWindowDraggingRects[i] = mWindowDraggingRects[length - 1];
+ length--;
+ } else {
+ i++;
+ }
+ }
+ mWindowDraggingFrames.resize(length);
+ mWindowDraggingRects.SetLength(length);
+
+ i = 0;
+ length = mWindowNoDraggingFrames.size();
+ while (i < length) {
+ if (!mWindowNoDraggingFrames[i].IsAlive() ||
+ mWindowNoDraggingFrames[i]->IsFrameModified()) {
+ mWindowNoDraggingFrames[i] = mWindowNoDraggingFrames[length - 1];
+ mWindowNoDraggingRects[i] = mWindowNoDraggingRects[length - 1];
+ length--;
+ } else {
+ i++;
+ }
+ }
+ mWindowNoDraggingFrames.resize(length);
+ mWindowNoDraggingRects.SetLength(length);
+}
+
+void
+nsDisplayListBuilder::ClearWindowDraggingRegion()
+{
+ mWindowDraggingFrames.clear();
+ mWindowDraggingRects.Clear();
+ mWindowNoDraggingFrames.clear();
+ mWindowNoDraggingRects.Clear();
+}
+
const uint32_t gWillChangeAreaMultiplier = 3;
static uint32_t GetLayerizationCost(const nsSize& aSize) {
// There's significant overhead for each layer created from Gecko
// (IPC+Shared Objects) and from the backend (like an OpenGL texture).
// Therefore we set a minimum cost threshold of a 64x64 area.
int minBudgetCost = 64 * 64;
uint32_t budgetCost =
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -899,16 +899,19 @@ public:
* collected dragging region; if the value is |no-drag|, the border box is
* subtracted from the region; if the value is |default|, that frame does
* not influence the window dragging region.
*/
void AdjustWindowDraggingRegion(nsIFrame* aFrame);
LayoutDeviceIntRegion GetWindowDraggingRegion() const;
+ void RemoveModifiedWindowDraggingRegion();
+ void ClearWindowDraggingRegion();
+
/**
* Allocate memory in our arena. It will only be freed when this display list
* builder is destroyed. This memory holds nsDisplayItems. nsDisplayItem
* destructors are called as soon as the item is no longer used.
*/
void* Allocate(size_t aSize, DisplayItemType aType);
void Destroy(DisplayItemType aType, void* aPtr);
@@ -1710,17 +1713,23 @@ private:
nsTArray<nsIFrame*> mModifiedFramesDuringBuilding;
// Relative to mCurrentFrame.
nsRect mVisibleRect;
nsRect mDirtyRect;
nsRegion mWindowExcludeGlassRegion;
nsRegion mWindowOpaqueRegion;
+
+ std::vector<WeakFrame> mWindowDraggingFrames;
+ nsTArray<pixman_box32_t> mWindowDraggingRects;
LayoutDeviceIntRegion mWindowDraggingRegion;
+
+ std::vector<WeakFrame> mWindowNoDraggingFrames;
+ nsTArray<pixman_box32_t> mWindowNoDraggingRects;
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
// 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.