mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-04 07:40:42 +00:00
Bug 805343. Identify DisplayItemDatas that are completely hidden by other opaque content in their ThebesLayer, and ignore them when we check to see whether there's an image we might need to invalidate. r=mattwoodrow
--HG-- extra : rebase_source : 7e68dc33324d8ff26286723bdbaaea18060354ac
This commit is contained in:
parent
07431e7fdb
commit
f3332e603a
@ -49,6 +49,7 @@ FrameLayerBuilder::DisplayItemData::DisplayItemData(LayerManagerData* aParent, u
|
||||
, mLayerState(aLayerState)
|
||||
, mUsed(true)
|
||||
, mIsInvalid(false)
|
||||
, mIsVisible(true)
|
||||
{
|
||||
}
|
||||
|
||||
@ -66,6 +67,7 @@ FrameLayerBuilder::DisplayItemData::DisplayItemData(DisplayItemData &toCopy)
|
||||
mContainerLayerGeneration = toCopy.mContainerLayerGeneration;
|
||||
mLayerState = toCopy.mLayerState;
|
||||
mUsed = toCopy.mUsed;
|
||||
mIsVisible = toCopy.mIsVisible;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1115,7 +1117,7 @@ FrameLayerBuilder::HasRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey
|
||||
}
|
||||
|
||||
void
|
||||
FrameLayerBuilder::IterateRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallback aCallback)
|
||||
FrameLayerBuilder::IterateVisibleRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallback aCallback)
|
||||
{
|
||||
nsTArray<DisplayItemData*> *array =
|
||||
reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty()));
|
||||
@ -1125,7 +1127,8 @@ FrameLayerBuilder::IterateRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallb
|
||||
|
||||
for (uint32_t i = 0; i < array->Length(); i++) {
|
||||
DisplayItemData* data = array->ElementAt(i);
|
||||
if (data->mDisplayItemKey != nsDisplayItem::TYPE_ZERO) {
|
||||
if (data->mDisplayItemKey != nsDisplayItem::TYPE_ZERO &&
|
||||
data->IsVisibleInLayer()) {
|
||||
aCallback(aFrame, data);
|
||||
}
|
||||
}
|
||||
@ -1841,7 +1844,7 @@ ContainerState::ThebesLayerData::Accumulate(ContainerState* aState,
|
||||
nsRegion opaqueClipped;
|
||||
nsRegionRectIterator iter(opaque);
|
||||
for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
|
||||
opaqueClipped.Or(opaqueClipped, aClip.ApproximateIntersect(*r));
|
||||
opaqueClipped.Or(opaqueClipped, aClip.ApproximateIntersectInner(*r));
|
||||
}
|
||||
|
||||
nsIntRegion opaquePixels = aState->ScaleRegionToInsidePixels(opaqueClipped, snap);
|
||||
@ -2456,7 +2459,8 @@ FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer,
|
||||
}
|
||||
}
|
||||
|
||||
AddLayerDisplayItem(aLayer, aItem, aClip, aLayerState, aTopLeft, tempManager, aGeometry);
|
||||
DisplayItemData* displayItemData =
|
||||
AddLayerDisplayItem(aLayer, aItem, aClip, aLayerState, aTopLeft, tempManager, aGeometry);
|
||||
|
||||
ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(aLayer);
|
||||
if (entry) {
|
||||
@ -2523,7 +2527,7 @@ FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer,
|
||||
}
|
||||
}
|
||||
ClippedDisplayItem* cdi =
|
||||
entry->mItems.AppendElement(ClippedDisplayItem(aItem, aClip,
|
||||
entry->mItems.AppendElement(ClippedDisplayItem(aItem, displayItemData, aClip,
|
||||
mContainerLayerGeneration));
|
||||
cdi->mInactiveLayerManager = tempManager;
|
||||
}
|
||||
@ -2598,7 +2602,7 @@ FrameLayerBuilder::ClippedDisplayItem::~ClippedDisplayItem()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FrameLayerBuilder::DisplayItemData*
|
||||
FrameLayerBuilder::AddLayerDisplayItem(Layer* aLayer,
|
||||
nsDisplayItem* aItem,
|
||||
const Clip& aClip,
|
||||
@ -2608,7 +2612,7 @@ FrameLayerBuilder::AddLayerDisplayItem(Layer* aLayer,
|
||||
nsAutoPtr<nsDisplayItemGeometry> aGeometry)
|
||||
{
|
||||
if (aLayer->Manager() != mRetainingManager)
|
||||
return;
|
||||
return nullptr;
|
||||
|
||||
DisplayItemData *data = StoreDataForFrame(aItem, aLayer, aLayerState);
|
||||
ThebesLayer *t = aLayer->AsThebesLayer();
|
||||
@ -2617,6 +2621,7 @@ FrameLayerBuilder::AddLayerDisplayItem(Layer* aLayer,
|
||||
data->mClip = aClip;
|
||||
}
|
||||
data->mInactiveManager = aManager;
|
||||
return data;
|
||||
}
|
||||
|
||||
nsIntPoint
|
||||
@ -3265,15 +3270,29 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
|
||||
int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
|
||||
|
||||
uint32_t i;
|
||||
// Update visible regions. We need perform visibility analysis again
|
||||
// because we may be asked to draw into part of a ThebesLayer that
|
||||
// isn't actually visible in the window (e.g., because a ThebesLayer
|
||||
// expanded its visible region to a rectangle internally), in which
|
||||
// case the mVisibleRect stored in the display item may be wrong.
|
||||
nsRegion visible = aRegionToDraw.ToAppUnits(appUnitsPerDevPixel);
|
||||
// Update visible rects in display items to reflect visibility
|
||||
// just considering items in this ThebesLayer. This is different from the
|
||||
// original visible rects, which describe which part of each item
|
||||
// is visible in the window. These can be larger than the original
|
||||
// visible rect, because we may be asked to draw into part of a
|
||||
// ThebesLayer that isn't actually visible in the window (e.g.,
|
||||
// because a ThebesLayer expanded its visible region to a rectangle
|
||||
// internally, or because we're caching prerendered content).
|
||||
// We also compute the intersection of those visible rects with
|
||||
// aRegionToDraw. These are the rectangles of each display item
|
||||
// that actually need to be drawn now.
|
||||
// Treat as visible everything this layer already contains or will
|
||||
// contain.
|
||||
nsIntRegion layerRegion;
|
||||
layerRegion.Or(aLayer->GetValidRegion(), aRegionToDraw);
|
||||
nsRegion visible = layerRegion.ToAppUnits(appUnitsPerDevPixel);
|
||||
visible.MoveBy(NSIntPixelsToAppUnits(offset.x, appUnitsPerDevPixel),
|
||||
NSIntPixelsToAppUnits(offset.y, appUnitsPerDevPixel));
|
||||
visible.ScaleInverseRoundOut(userData->mXScale, userData->mYScale);
|
||||
nsRegion toDraw = aRegionToDraw.ToAppUnits(appUnitsPerDevPixel);
|
||||
toDraw.MoveBy(NSIntPixelsToAppUnits(offset.x, appUnitsPerDevPixel),
|
||||
NSIntPixelsToAppUnits(offset.y, appUnitsPerDevPixel));
|
||||
toDraw.ScaleInverseRoundOut(userData->mXScale, userData->mYScale);
|
||||
|
||||
for (i = items.Length(); i > 0; --i) {
|
||||
ClippedDisplayItem* cdi = &items[i - 1];
|
||||
@ -3289,29 +3308,28 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
|
||||
(cdi->mClip.mRoundedClipRects.IsEmpty() &&
|
||||
cdi->mClip.mClipRect.Contains(visible.GetBounds()))) {
|
||||
cdi->mItem->RecomputeVisibility(builder, &visible);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do a little dance to account for the fact that we're clipping
|
||||
// to cdi->mClipRect
|
||||
nsRegion clipped;
|
||||
clipped.And(visible, cdi->mClip.mClipRect);
|
||||
nsRegion finalClipped = clipped;
|
||||
cdi->mItem->RecomputeVisibility(builder, &finalClipped);
|
||||
// If we have rounded clip rects, don't subtract from the visible
|
||||
// region since we aren't displaying everything inside the rect.
|
||||
if (cdi->mClip.mRoundedClipRects.IsEmpty()) {
|
||||
nsRegion removed;
|
||||
removed.Sub(clipped, finalClipped);
|
||||
nsRegion newVisible;
|
||||
newVisible.Sub(visible, removed);
|
||||
// Don't let the visible region get too complex.
|
||||
if (newVisible.GetNumRects() <= 15) {
|
||||
visible = newVisible;
|
||||
} else {
|
||||
// Do a little dance to account for the fact that we're clipping
|
||||
// to cdi->mClipRect
|
||||
nsRegion clipped;
|
||||
clipped.And(visible, cdi->mClip.mClipRect);
|
||||
nsRegion finalClipped = clipped;
|
||||
cdi->mItem->RecomputeVisibility(builder, &finalClipped);
|
||||
// If we have rounded clip rects, don't subtract from the visible
|
||||
// region since we aren't displaying everything inside the rect.
|
||||
if (cdi->mClip.mRoundedClipRects.IsEmpty()) {
|
||||
nsRegion removed;
|
||||
removed.Sub(clipped, finalClipped);
|
||||
nsRegion newVisible;
|
||||
newVisible.Sub(visible, removed);
|
||||
// Don't let the visible region get too complex.
|
||||
if (newVisible.GetNumRects() <= 15) {
|
||||
visible = newVisible;
|
||||
}
|
||||
}
|
||||
if (!cdi->mClip.IsRectClippedByRoundedCorner(cdi->mItem->GetVisibleRect())) {
|
||||
cdi->mClip.RemoveRoundedCorners();
|
||||
}
|
||||
}
|
||||
if (!cdi->mClip.IsRectClippedByRoundedCorner(cdi->mItem->GetVisibleRect())) {
|
||||
cdi->mClip.RemoveRoundedCorners();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3324,8 +3342,13 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
|
||||
for (i = 0; i < items.Length(); ++i) {
|
||||
ClippedDisplayItem* cdi = &items[i];
|
||||
|
||||
if (cdi->mItem->GetVisibleRect().IsEmpty())
|
||||
if (cdi->mData) {
|
||||
cdi->mData->SetIsVisibleInLayer(!cdi->mItem->GetVisibleRect().IsEmpty());
|
||||
}
|
||||
|
||||
if (!toDraw.Intersects(cdi->mItem->GetVisibleRect())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the new desired clip state is different from the current state,
|
||||
// update the clip.
|
||||
@ -3503,7 +3526,7 @@ FrameLayerBuilder::Clip::AddRoundedRectPathTo(gfxContext* aContext,
|
||||
}
|
||||
|
||||
nsRect
|
||||
FrameLayerBuilder::Clip::ApproximateIntersect(const nsRect& aRect) const
|
||||
FrameLayerBuilder::Clip::ApproximateIntersectInner(const nsRect& aRect) const
|
||||
{
|
||||
nsRect r = aRect;
|
||||
if (mHaveClipRect) {
|
||||
|
@ -96,6 +96,7 @@ public:
|
||||
typedef layers::ThebesLayer ThebesLayer;
|
||||
typedef layers::ImageLayer ImageLayer;
|
||||
typedef layers::LayerManager LayerManager;
|
||||
class DisplayItemData;
|
||||
|
||||
FrameLayerBuilder() :
|
||||
mRetainingManager(nullptr),
|
||||
@ -263,13 +264,13 @@ public:
|
||||
* then this is the temporary layer manager to draw with.
|
||||
*/
|
||||
struct Clip;
|
||||
void AddLayerDisplayItem(Layer* aLayer,
|
||||
nsDisplayItem* aItem,
|
||||
const Clip& aClip,
|
||||
LayerState aLayerState,
|
||||
const nsPoint& aTopLeft,
|
||||
LayerManager* aManager,
|
||||
nsAutoPtr<nsDisplayItemGeometry> aGeometry);
|
||||
DisplayItemData* AddLayerDisplayItem(Layer* aLayer,
|
||||
nsDisplayItem* aItem,
|
||||
const Clip& aClip,
|
||||
LayerState aLayerState,
|
||||
const nsPoint& aTopLeft,
|
||||
LayerManager* aManager,
|
||||
nsAutoPtr<nsDisplayItemGeometry> aGeometry);
|
||||
|
||||
/**
|
||||
* Record aItem as a display item that is rendered by the ThebesLayer
|
||||
@ -319,10 +320,9 @@ public:
|
||||
*/
|
||||
static bool HasRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey);
|
||||
|
||||
class DisplayItemData;
|
||||
typedef void (*DisplayItemDataCallback)(nsIFrame *aFrame, DisplayItemData* aItem);
|
||||
|
||||
static void IterateRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallback aCallback);
|
||||
static void IterateVisibleRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallback aCallback);
|
||||
|
||||
/**
|
||||
* Save transform that was in aLayer when we last painted, and the position
|
||||
@ -417,7 +417,7 @@ public:
|
||||
// Return a rectangle contained in the intersection of aRect with this
|
||||
// clip region. Tries to return the largest possible rectangle, but may
|
||||
// not succeed.
|
||||
nsRect ApproximateIntersect(const nsRect& aRect) const;
|
||||
nsRect ApproximateIntersectInner(const nsRect& aRect) const;
|
||||
|
||||
// Returns false if aRect is definitely not clipped by a rounded corner in
|
||||
// this clip. Returns true if aRect is clipped by a rounded corner in this
|
||||
@ -477,6 +477,9 @@ public:
|
||||
uint32_t GetDisplayItemKey() { return mDisplayItemKey; }
|
||||
Layer* GetLayer() { return mLayer; }
|
||||
void Invalidate() { mIsInvalid = true; }
|
||||
bool IsVisibleInLayer() { return mIsVisible; }
|
||||
void SetIsVisibleInLayer(bool aIsVisible) { mIsVisible = aIsVisible; }
|
||||
|
||||
protected:
|
||||
|
||||
DisplayItemData(LayerManagerData* aParent, uint32_t aKey, Layer* aLayer, LayerState aLayerState, uint32_t aGeneration);
|
||||
@ -525,7 +528,15 @@ public:
|
||||
* paint) has been updated in the current paint.
|
||||
*/
|
||||
bool mUsed;
|
||||
/**
|
||||
* True if the entire display item needs to be invalidated.
|
||||
*/
|
||||
bool mIsInvalid;
|
||||
/**
|
||||
* True if the display item is visible in its layer, otherwise
|
||||
* it's completely covered by opaque content in its ThebesLayer.
|
||||
*/
|
||||
bool mIsVisible;
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -592,14 +603,17 @@ protected:
|
||||
* mItem always has an underlying frame.
|
||||
*/
|
||||
struct ClippedDisplayItem {
|
||||
ClippedDisplayItem(nsDisplayItem* aItem, const Clip& aClip, uint32_t aGeneration)
|
||||
: mItem(aItem), mClip(aClip), mContainerLayerGeneration(aGeneration)
|
||||
ClippedDisplayItem(nsDisplayItem* aItem, DisplayItemData* aData,
|
||||
const Clip& aClip, uint32_t aGeneration)
|
||||
: mItem(aItem), mData(aData), mClip(aClip),
|
||||
mContainerLayerGeneration(aGeneration)
|
||||
{
|
||||
}
|
||||
|
||||
~ClippedDisplayItem();
|
||||
|
||||
nsDisplayItem* mItem;
|
||||
DisplayItemData* mData;
|
||||
|
||||
/**
|
||||
* If the display item is being rendered as an inactive
|
||||
|
@ -341,7 +341,7 @@ ImageLoader::DoRedraw(FrameSet* aFrameSet)
|
||||
nsIFrame* frame = aFrameSet->ElementAt(i);
|
||||
|
||||
if (frame->GetStyleVisibility()->IsVisible()) {
|
||||
FrameLayerBuilder::IterateRetainedDataFor(frame, InvalidateImagesCallback);
|
||||
FrameLayerBuilder::IterateVisibleRetainedDataFor(frame, InvalidateImagesCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user