Bug 539356 - Add an option for frames to invalid just a rect instead of the frame bounds. r=roc

This commit is contained in:
Matt Woodrow 2012-08-29 17:48:45 +12:00
parent 68d1759f83
commit daef8103fd
6 changed files with 97 additions and 17 deletions

View File

@ -2114,7 +2114,8 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
continue;
}
if (item->IsInvalid()) {
nsRect invalid;
if (item->IsInvalid(invalid)) {
ownLayer->SetInvalidRectToVisibleRegion();
}
@ -2252,8 +2253,10 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
ThebesDisplayItemLayerUserData* data =
static_cast<ThebesDisplayItemLayerUserData*>(newThebesLayer->GetUserData(&gThebesDisplayItemLayerUserData));
// If the frame is marked as invalidated then we want to invalidate both the old and new bounds,
// otherwise we only want to invalidate the changed areas.
// If the frame is marked as invalidated, and didn't specify a rect to invalidate then we want to
// invalidate both the old and new bounds, otherwise we only want to invalidate the changed areas.
// If we do get an invalid rect, then we want to add this on top of the change areas.
nsRect invalid;
nsRegion combined;
if (!oldLayer) {
// This item is being added for the first time, invalidate its entire area.
@ -2262,7 +2265,7 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
#ifdef DEBUG_INVALIDATIONS
printf("Display item type %s(%p) added to layer %p!\n", aItem->Name(), f, aNewLayer);
#endif
} else if (aItem->IsInvalid()) {
} else if (aItem->IsInvalid(invalid) && invalid.IsEmpty()) {
// Either layout marked item as needing repainting, invalidate the entire old and new areas.
combined.Or(geometry->ComputeInvalidationRegion(), oldGeometry->ComputeInvalidationRegion());
#ifdef DEBUG_INVALIDATIONS
@ -2277,6 +2280,9 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
oldClip->AddOffsetAndComputeDifference(shift, oldGeometry->ComputeInvalidationRegion(),
aClip, geometry->ComputeInvalidationRegion(),
&combined);
// Add in any rect that the frame specified
combined = combined.Or(combined, invalid);
#ifdef DEBUG_INVALIDATIONS
if (!combined.IsEmpty()) {
printf("Display item type %s(%p) (in layer %p) changed geometry!\n", aItem->Name(), f, aNewLayer);

View File

@ -774,7 +774,11 @@ public:
* Checks if the frame(s) owning this display item have been marked as invalid,
* and needing repainting.
*/
virtual bool IsInvalid() { return mFrame ? mFrame->IsInvalid() : false; }
virtual bool IsInvalid(nsRect& aRect) {
bool result = mFrame ? mFrame->IsInvalid(aRect) : false;
aRect += ToReferenceFrame();
return result;
}
/**
* Creates and initializes an nsDisplayItemGeometry object that retains the current
@ -2005,17 +2009,21 @@ public:
{
aFrames->AppendElements(mMergedFrames);
}
virtual bool IsInvalid()
virtual bool IsInvalid(nsRect& aRect)
{
if (mFrame->IsInvalid()) {
if (mFrame->IsInvalid(aRect) && aRect.IsEmpty()) {
return true;
}
nsRect temp;
for (uint32_t i = 0; i < mMergedFrames.Length(); i++) {
if (mMergedFrames[i]->IsInvalid()) {
if (mMergedFrames[i]->IsInvalid(temp) && temp.IsEmpty()) {
aRect.SetEmpty();
return true;
}
aRect = aRect.Union(temp);
}
return false;
aRect += ToReferenceFrame();
return !aRect.IsEmpty();
}
NS_DISPLAY_DECL_NAME("WrapList", TYPE_WRAP_LIST)

View File

@ -4806,12 +4806,50 @@ nsIFrame::InvalidateFrame()
if (!parent) {
SchedulePaint();
}
if (HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) {
Properties().Delete(InvalidationRect());
RemoveStateBits(NS_FRAME_HAS_INVALID_RECT);
}
}
void
nsIFrame::InvalidateFrameWithRect(const nsRect& aRect)
{
bool alreadyInvalid = false;
if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) {
InvalidateFrame();
} else {
alreadyInvalid = true;
}
nsRect *rect = static_cast<nsRect*>(Properties().Get(InvalidationRect()));
if (!rect) {
if (alreadyInvalid) {
return;
}
rect = new nsRect();
Properties().Set(InvalidationRect(), rect);
AddStateBits(NS_FRAME_HAS_INVALID_RECT);
}
*rect = rect->Union(aRect);
}
bool
nsIFrame::IsInvalid()
nsIFrame::IsInvalid(nsRect& aRect)
{
return HasAnyStateBits(NS_FRAME_NEEDS_PAINT);
if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) {
return false;
}
if (HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) {
nsRect *rect = static_cast<nsRect*>(Properties().Get(InvalidationRect()));
NS_ASSERTION(rect, "Must have an invalid rect if NS_FRAME_HAS_INVALID_RECT is set!");
aRect = *rect;
} else {
aRect.SetEmpty();
}
return true;
}
void

View File

@ -319,6 +319,10 @@ typedef uint64_t nsFrameState;
// have no display items.
#define NS_FRAME_ALL_DESCENDANTS_NEED_PAINT NS_FRAME_STATE_BIT(51)
// Frame is marked as NS_FRAME_NEEDS_PAINT and also has an explicit
// rect stored to invalidate.
#define NS_FRAME_HAS_INVALID_RECT NS_FRAME_STATE_BIT(52)
// Box layout bits
#define NS_STATE_IS_HORIZONTAL NS_FRAME_STATE_BIT(22)
#define NS_STATE_IS_DIRECTION_NORMAL NS_FRAME_STATE_BIT(31)
@ -955,6 +959,8 @@ public:
NS_DECLARE_FRAME_PROPERTY(CachedBackgroundImage, DestroySurface)
NS_DECLARE_FRAME_PROPERTY(InvalidationRect, DestroyRect)
/**
* Return the distance between the border edge of the frame and the
* margin edge of the frame. Like GetRect(), returns the dimensions
@ -2179,6 +2185,15 @@ public:
* container types.
*/
virtual void InvalidateFrame();
/**
* Same as InvalidateFrame(), but only mark a fixed rect as needing
* repainting.
*
* @param aRect The rect to invalidate, relative to the TopLeft of the
* frame's border box.
*/
virtual void InvalidateFrameWithRect(const nsRect& aRect);
/**
* Calls InvalidateFrame() on all frames descendant frames (including
@ -2192,8 +2207,13 @@ public:
/**
* Checks if a frame has had InvalidateFrame() called on it since the
* last paint.
*
* If true, then the invalid rect is returned in aRect, with an
* empty rect meaning all pixels drawn by this frame should be
* invalidated.
* If false, aRect is left unchanged.
*/
bool IsInvalid();
bool IsInvalid(nsRect& aRect);
/**
* Check if any frame within the frame subtree (including this frame)

View File

@ -587,12 +587,16 @@ nsImageFrame::OnDataAvailable(imgIRequest *aRequest,
// from
if (!aCurrentFrame)
return NS_OK;
#ifdef DEBUG_decode
printf("Source rect (%d,%d,%d,%d)\n",
aRect->x, aRect->y, aRect->width, aRect->height);
#endif
InvalidateFrame();
if (aRect->IsEqualInterior(nsIntRect::GetMaxSizedIntRect())) {
InvalidateFrame();
} else {
InvalidateFrameWithRect(SourceRectToDest(*aRect));
}
return NS_OK;
}
@ -671,8 +675,11 @@ nsImageFrame::FrameChanged(imgIRequest *aRequest,
return NS_OK;
}
// Update border+content to account for image change
InvalidateFrame();
if (aDirtyRect->IsEqualInterior(nsIntRect::GetMaxSizedIntRect())) {
InvalidateFrame();
} else {
InvalidateFrameWithRect(SourceRectToDest(*aDirtyRect));
}
return NS_OK;
}

View File

@ -155,7 +155,8 @@ public:
void ClearInvalidRegion() { mInvalidRegion.SetEmpty(); }
const nsRegion& GetInvalidRegion() {
if (!IsInvalid()) {
nsRect rect;
if (!IsInvalid(rect)) {
mInvalidRegion.SetEmpty();
}
return mInvalidRegion;