--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -1320,16 +1320,17 @@ WebRenderCommandBuilder::CreateWebRender
}/* else if (itemType == DisplayItemType::TYPE_FOREIGN_OBJECT) {
// We do not want to apply grouping inside <foreignObject>.
// TODO: TYPE_FOREIGN_OBJECT does not exist yet, make it exist
mDoGrouping = false;
}*/
// Note: this call to CreateWebRenderCommands can recurse back into
// this function if the |item| is a wrapper for a sublist.
+ item->SetPaintRect(item->GetBuildingRect());
bool createdWRCommands =
item->CreateWebRenderCommands(aBuilder, aResources, aSc, mManager,
aDisplayListBuilder);
if (!createdWRCommands) {
PushItemAsImage(item, aBuilder, aResources, aSc, aDisplayListBuilder);
}
}
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -285,20 +285,21 @@ DisplayItemData::EndUpdate(nsAutoPtr<nsD
mChangedFrameInvalidations.SetEmpty();
mItem = nullptr;
EndUpdate();
}
void
DisplayItemData::BeginUpdate(Layer* aLayer, LayerState aState,
+ bool aFirstUpdate,
nsDisplayItem* aItem /* = nullptr */)
{
BeginUpdate(aLayer, aState, aItem,
- aItem ? aItem->IsReused() : false,
+ (aItem && !aFirstUpdate) ? aItem->IsReused() : false,
aItem ? aItem->HasMergedFrames() : false);
}
void
DisplayItemData::BeginUpdate(Layer* aLayer, LayerState aState,
nsDisplayItem* aItem, bool aIsReused,
bool aIsMerged)
{
@@ -569,16 +570,17 @@ public:
* need to update our regions.
* @param aVisibleRect the area of the item that's visible
* @param aSolidColor if non-null, the visible area of the item is
* a constant color given by *aSolidColor
*/
void Accumulate(ContainerState* aState,
nsDisplayItem* aItem,
const nsIntRect& aVisibleRect,
+ const nsRect& aContentRect,
const DisplayItemClip& aClip,
LayerState aLayerState,
nsDisplayList *aList,
DisplayItemEntryType aType);
AnimatedGeometryRoot* GetAnimatedGeometryRoot() { return mAnimatedGeometryRoot; }
/**
* A region including the horizontal pan, vertical pan, and no action regions.
@@ -1691,16 +1693,20 @@ public:
// The region for which display item visibility for this layer has already
// been calculated. Used to reduce the number of calls to
// RecomputeVisibilityForItems if it is known in advance that a larger
// region will be painted during a transaction than in a single call to
// DrawPaintedLayer, for example when progressive paint is enabled.
nsIntRegion mVisibilityComputedRegion;
+ // The area for which we called RecomputeVisibilityForItems on the
+ // previous paint.
+ nsRect mPreviousRecomputeVisibilityRect;
+
// The number of items assigned to this layer on the previous paint.
size_t mLastItemCount;
// The translation set on this PaintedLayer before we started updating the
// layer tree.
nsIntPoint mLastPaintOffset;
// Temporary state only valid during the FrameLayerBuilder's lifetime.
@@ -3607,16 +3613,17 @@ IsItemAreaInWindowOpaqueRegion(nsDisplay
}
return aBuilder->GetWindowOpaqueRegion().Contains(aComponentAlphaBounds);
}
void
PaintedLayerData::Accumulate(ContainerState* aState,
nsDisplayItem* aItem,
const nsIntRect& aVisibleRect,
+ const nsRect& aContentRect,
const DisplayItemClip& aClip,
LayerState aLayerState,
nsDisplayList* aList,
DisplayItemEntryType aType)
{
FLB_LOG_PAINTED_LAYER_DECISION(this, "Accumulating dp=%s(%p), f=%p against pld=%p\n", aItem->Name(), aItem, aItem->Frame(), this);
const bool hasOpacity = mOpacityIndices.Length() > 0;
@@ -3624,17 +3631,17 @@ PaintedLayerData::Accumulate(ContainerSt
const DisplayItemClip* oldClip = mItemClip;
mItemClip = &aClip;
if (aType == DisplayItemEntryType::POP_OPACITY) {
MOZ_ASSERT(!mOpacityIndices.IsEmpty());
mOpacityIndices.RemoveLastElement();
AssignedDisplayItem item(aItem, aLayerState,
- nullptr, aType, hasOpacity);
+ nullptr, aContentRect, aType, hasOpacity);
mAssignedDisplayItems.AppendElement(Move(item));
return;
}
if (aState->mBuilder->NeedToForceTransparentSurfaceForItem(aItem)) {
mForceTransparentSurface = true;
}
@@ -3663,17 +3670,17 @@ PaintedLayerData::Accumulate(ContainerSt
DisplayItemData* currentData =
aItem->HasMergedFrames() ? nullptr : aItem->GetDisplayItemData();
DisplayItemData* oldData =
aState->mLayerBuilder->GetOldLayerForFrame(aItem->Frame(),
aItem->GetPerFrameKey(),
currentData);
AssignedDisplayItem item(aItem, aLayerState,
- oldData, aType, hasOpacity);
+ oldData, aContentRect, aType, hasOpacity);
mAssignedDisplayItems.AppendElement(Move(item));
if (aType == DisplayItemEntryType::PUSH_OPACITY) {
mOpacityIndices.AppendElement(mAssignedDisplayItems.Length() - 1);
}
if (aItem->MustPaintOnContentSide()) {
mShouldPaintOnContentSide = true;
@@ -4837,17 +4844,17 @@ ContainerState::ProcessDisplayItems(nsDi
nsDisplayLayerEventRegions* eventRegions =
static_cast<nsDisplayLayerEventRegions*>(item);
paintedLayerData->AccumulateEventRegions(this, eventRegions);
} else if (itemType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO) {
nsDisplayCompositorHitTestInfo* hitTestInfo =
static_cast<nsDisplayCompositorHitTestInfo*>(item);
paintedLayerData->AccumulateHitTestInfo(this, hitTestInfo);
} else {
- paintedLayerData->Accumulate(this, item, itemVisibleRect, itemClip,
+ paintedLayerData->Accumulate(this, item, itemVisibleRect, itemContent, itemClip,
layerState, aList, marker);
if (!paintedLayerData->mLayer) {
// Try to recycle the old layer of this display item.
RefPtr<PaintedLayer> layer =
AttemptToRecyclePaintedLayer(animatedGeometryRoot, item,
topLeft, referenceFrame);
if (layer) {
@@ -5163,72 +5170,75 @@ FrameLayerBuilder::AddPaintedDisplayItem
}
DisplayItemData*
FrameLayerBuilder::StoreDataForFrame(nsDisplayItem* aItem, Layer* aLayer,
LayerState aState, DisplayItemData* aData)
{
if (aData) {
if (!aData->mUsed) {
- aData->BeginUpdate(aLayer, aState, aItem);
+ aData->BeginUpdate(aLayer, aState, false, aItem);
}
return aData;
}
LayerManagerData* lmd = static_cast<LayerManagerData*>
(mRetainingManager->GetUserData(&gLayerManagerUserData));
RefPtr<DisplayItemData> data =
new (aItem->Frame()->PresContext()) DisplayItemData(lmd, aItem->GetPerFrameKey(), aLayer);
if (!data->HasMergedFrames()) {
aItem->SetDisplayItemData(data);
}
- data->BeginUpdate(aLayer, aState, aItem);
+ data->BeginUpdate(aLayer, aState, true, aItem);
lmd->mDisplayItems.PutEntry(data);
return data;
}
void
FrameLayerBuilder::StoreDataForFrame(nsIFrame* aFrame,
uint32_t aDisplayItemKey,
Layer* aLayer,
LayerState aState)
{
DisplayItemData* oldData = GetDisplayItemData(aFrame, aDisplayItemKey);
if (oldData && oldData->mFrameList.Length() == 1) {
- oldData->BeginUpdate(aLayer, aState);
+ oldData->BeginUpdate(aLayer, aState, false);
return;
}
LayerManagerData* lmd = static_cast<LayerManagerData*>
(mRetainingManager->GetUserData(&gLayerManagerUserData));
RefPtr<DisplayItemData> data =
new (aFrame->PresContext()) DisplayItemData(lmd, aDisplayItemKey, aLayer, aFrame);
- data->BeginUpdate(aLayer, aState);
+ data->BeginUpdate(aLayer, aState, true);
lmd->mDisplayItems.PutEntry(data);
}
AssignedDisplayItem::AssignedDisplayItem(nsDisplayItem* aItem,
LayerState aLayerState,
DisplayItemData* aData,
+ const nsRect& aContentRect,
DisplayItemEntryType aType,
const bool aHasOpacity)
: mItem(aItem)
, mLayerState(aLayerState)
, mDisplayItemData(aData)
+ , mContentRect(aContentRect)
+ , mType(aType)
, mReused(aItem->IsReused())
, mMerged(aItem->HasMergedFrames())
- , mType(aType)
, mHasOpacity(aHasOpacity)
+ , mHasPaintRect(aItem->HasPaintRect())
{}
AssignedDisplayItem::~AssignedDisplayItem()
{
if (mInactiveLayerManager) {
mInactiveLayerManager->SetUserData(&gLayerManagerLayerBuilder, nullptr);
}
}
@@ -6152,16 +6162,17 @@ static void DebugPaintItem(DrawTarget& a
aItem->SetPainted();
}
#endif
/* static */ void
FrameLayerBuilder::RecomputeVisibilityForItems(nsTArray<AssignedDisplayItem>& aItems,
nsDisplayListBuilder *aBuilder,
const nsIntRegion& aRegionToDraw,
+ nsRect& aPreviousRectToDraw,
const nsIntPoint& aOffset,
int32_t aAppUnitsPerDevPixel,
float aXScale,
float aYScale)
{
uint32_t i;
// Update visible regions. We perform visibility analysis to take account
// of occlusion culling.
@@ -6171,16 +6182,22 @@ FrameLayerBuilder::RecomputeVisibilityFo
visible.ScaleInverseRoundOut(aXScale, aYScale);
for (i = aItems.Length(); i > 0; --i) {
AssignedDisplayItem* cdi = &aItems[i - 1];
if (!cdi->mItem) {
continue;
}
+ if (cdi->mHasPaintRect &&
+ !cdi->mContentRect.Intersects(visible.GetBounds()) &&
+ !cdi->mContentRect.Intersects(aPreviousRectToDraw)) {
+ continue;
+ }
+
if (cdi->mType == DisplayItemEntryType::POP_OPACITY ||
(cdi->mType == DisplayItemEntryType::ITEM && cdi->mHasOpacity)) {
// The visibility calculations are skipped when the item is an effect end
// marker, or when the display item is within a flattened opacity group.
// This is because RecomputeVisibility has already been called for the
// group item, and all the children.
continue;
}
@@ -6212,16 +6229,18 @@ FrameLayerBuilder::RecomputeVisibilityFo
nsRegion newVisible;
newVisible.Sub(visible, removed);
// Don't let the visible region get too complex.
if (newVisible.GetNumRects() <= 15) {
visible = Move(newVisible);
}
}
}
+
+ aPreviousRectToDraw = visible.GetBounds();
}
/**
* Sets the clip chain and starts a new opacity group.
*/
static void
PushOpacity(gfxContext* aContext,
const nsRect& aPaintRect,
@@ -6527,16 +6546,17 @@ FrameLayerBuilder::DrawPaintedLayer(Pain
!layerBuilder->GetContainingPaintedLayerData()) {
// Recompute visibility of items in our PaintedLayer, if required. Note
// that this recomputes visibility for all descendants of our display
// items too, so there's no need to do this for the items in inactive
// PaintedLayers. If aDirtyRegion has not changed since the previous call
// then we can skip this.
int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
RecomputeVisibilityForItems(userData->mItems, builder, aDirtyRegion,
+ userData->mPreviousRecomputeVisibilityRect,
offset, appUnitsPerDevPixel,
userData->mXScale, userData->mYScale);
userData->mVisibilityComputedRegion = aDirtyRegion;
}
if (shouldDrawRectsSeparately) {
for (auto iter = aRegionToDraw.RectIter(); !iter.Done(); iter.Next()) {
const nsIntRect& iterRect = iter.Get();
--- a/layout/painting/FrameLayerBuilder.h
+++ b/layout/painting/FrameLayerBuilder.h
@@ -157,16 +157,17 @@ private:
* Updates the contents of this item to a new set of data, instead of allocating a new
* object.
* Set the passed in parameters, and clears the opt layer and inactive manager.
* Parent, and display item key are assumed to be the same.
*
* EndUpdate must be called before the end of the transaction to complete the update.
*/
void BeginUpdate(layers::Layer* aLayer, LayerState aState,
+ bool aFirstUpdate,
nsDisplayItem* aItem = nullptr);
void BeginUpdate(layers::Layer* aLayer, LayerState aState,
nsDisplayItem* aItem, bool aIsReused, bool aIsMerged);
/**
* Completes the update of this, and removes any references to data that won't live
* longer than the transaction.
*
@@ -217,36 +218,38 @@ public:
bool mIsInfinite;
};
struct AssignedDisplayItem
{
AssignedDisplayItem(nsDisplayItem* aItem,
LayerState aLayerState,
DisplayItemData* aData,
+ const nsRect& aContentRect,
DisplayItemEntryType aType,
const bool aHasOpacity);
~AssignedDisplayItem();
nsDisplayItem* mItem;
LayerState mLayerState;
DisplayItemData* mDisplayItemData;
+ nsRect mContentRect;
/**
* If the display item is being rendered as an inactive
* layer, then this stores the layer manager being
* used for the inactive transaction.
*/
RefPtr<layers::LayerManager> mInactiveLayerManager;
+ DisplayItemEntryType mType;
bool mReused;
bool mMerged;
-
- DisplayItemEntryType mType;
bool mHasOpacity;
+ bool mHasPaintRect;
};
struct ContainerLayerParameters {
ContainerLayerParameters()
: mXScale(1)
, mYScale(1)
, mLayerContentsVisibleRect(nullptr)
@@ -660,16 +663,17 @@ protected:
* These are only stored during the paint process, so that the
* DrawPaintedLayer callback can figure out which items to draw for the
* PaintedLayer.
*/
static void RecomputeVisibilityForItems(nsTArray<AssignedDisplayItem>& aItems,
nsDisplayListBuilder* aBuilder,
const nsIntRegion& aRegionToDraw,
+ nsRect& aPreviousRectToDraw,
const nsIntPoint& aOffset,
int32_t aAppUnitsPerDevPixel,
float aXScale,
float aYScale);
void PaintItems(nsTArray<AssignedDisplayItem>& aItems,
const nsIntRect& aRect,
gfxContext* aContext,
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -3091,16 +3091,17 @@ nsDisplayItem::nsDisplayItem(nsDisplayLi
const ActiveScrolledRoot* aActiveScrolledRoot)
: mFrame(aFrame)
, mActiveScrolledRoot(aActiveScrolledRoot)
, mAnimatedGeometryRoot(nullptr)
, mForceNotVisible(aBuilder->IsBuildingInvisibleItems())
, mDisableSubpixelAA(false)
, mReusedItem(false)
, mBackfaceHidden(mFrame->In3DContextAndBackfaceIsHidden())
+ , mPaintRectValid(false)
#ifdef MOZ_DUMP_PAINTING
, mPainted(false)
#endif
{
MOZ_COUNT_CTOR(nsDisplayItem);
if (aBuilder->IsRetainingDisplayList()) {
mFrame->AddDisplayItem(this);
}
@@ -9590,17 +9591,17 @@ nsDisplayMask::PaintMask(nsDisplayListBu
{
MOZ_ASSERT(aMaskContext->GetDrawTarget()->GetFormat() == SurfaceFormat::A8);
imgDrawingParams imgParmas(aBuilder->ShouldSyncDecodeImages()
? imgIContainer::FLAG_SYNC_DECODE
: imgIContainer::FLAG_SYNC_DECODE_IF_FAST);
nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
nsSVGIntegrationUtils::PaintFramesParams params(*aMaskContext,
- mFrame, GetPaintRect(),
+ mFrame, GetBuildingRect(),
borderArea, aBuilder,
nullptr,
mHandleOpacity, imgParmas);
ComputeMaskGeometry(params);
nsSVGIntegrationUtils::PaintMask(params);
nsDisplayMaskGeometry::UpdateDrawResult(this, imgParmas.result);
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -2095,16 +2095,17 @@ public:
, mClip(nullptr)
, mActiveScrolledRoot(nullptr)
, mReferenceFrame(nullptr)
, mAnimatedGeometryRoot(nullptr)
, mForceNotVisible(false)
, mDisableSubpixelAA(false)
, mReusedItem(false)
, mBackfaceHidden(mFrame->In3DContextAndBackfaceIsHidden())
+ , mPaintRectValid(false)
#ifdef MOZ_DUMP_PAINTING
, mPainted(false)
#endif
{
MOZ_COUNT_CTOR(nsDisplayItem);
}
protected:
@@ -2168,16 +2169,17 @@ public:
, mAnimatedGeometryRoot(aOther.mAnimatedGeometryRoot)
, mToReferenceFrame(aOther.mToReferenceFrame)
, mBuildingRect(aOther.mBuildingRect)
, mPaintRect(aOther.mPaintRect)
, mForceNotVisible(aOther.mForceNotVisible)
, mDisableSubpixelAA(aOther.mDisableSubpixelAA)
, mReusedItem(false)
, mBackfaceHidden(mFrame->In3DContextAndBackfaceIsHidden())
+ , mPaintRectValid(false)
#ifdef MOZ_DUMP_PAINTING
, mPainted(false)
#endif
{
MOZ_COUNT_CTOR(nsDisplayItem);
}
@@ -2655,17 +2657,19 @@ public:
void SetBuildingRect(const nsRect& aBuildingRect)
{
mPaintRect = mBuildingRect = aBuildingRect;
}
void SetPaintRect(const nsRect& aPaintRect) {
mPaintRect = aPaintRect;
- }
+ mPaintRectValid = true;
+ }
+ bool HasPaintRect() const { return mPaintRectValid; }
/**
* Returns the building rect for the children, relative to their
* reference frame. Can be different from mBuildingRect for nsDisplayTransform,
* since the reference frame for the children is different from the reference
* frame for the item itself.
*/
virtual const nsRect& GetBuildingRectForChildren() const { return mBuildingRect; }
@@ -2880,16 +2884,17 @@ protected:
mozilla::DebugOnly<uintptr_t> mOldList;
OldListIndex mOldListIndex;
bool mForceNotVisible;
bool mDisableSubpixelAA;
bool mReusedItem;
bool mBackfaceHidden;
+ bool mPaintRectValid;
#ifdef MOZ_DUMP_PAINTING
// True if this frame has been painted.
bool mPainted;
#endif
struct {
RefPtr<const DisplayItemClipChain> mClipChain;
const DisplayItemClip* mClip;