Bug 798964 - Don't invalidate nsDisplayBackgroundColor if only the image changed. r=roc

This commit is contained in:
Matt Woodrow 2012-11-07 11:04:53 +13:00
parent fe45b184c8
commit ced424bb37
5 changed files with 89 additions and 7 deletions

View File

@ -48,6 +48,7 @@ FrameLayerBuilder::DisplayItemData::DisplayItemData(LayerManagerData* aParent, u
, mContainerLayerGeneration(aGeneration)
, mLayerState(aLayerState)
, mUsed(true)
, mIsInvalid(false)
{
}
@ -1020,6 +1021,7 @@ FrameLayerBuilder::UpdateDisplayItemDataForFrame(nsRefPtrHashKey<DisplayItemData
}
data->mUsed = false;
data->mIsInvalid = false;
return PL_DHASH_NEXT;
}
@ -1112,6 +1114,20 @@ FrameLayerBuilder::HasRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey
return false;
}
void
FrameLayerBuilder::IterateRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallback aCallback)
{
nsTArray<DisplayItemData*> *array =
reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty()));
if (!array) {
return;
}
for (uint32_t i = 0; i < array->Length(); i++) {
aCallback(aFrame, array->ElementAt(i));
}
}
FrameLayerBuilder::DisplayItemData*
FrameLayerBuilder::GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey)
{
@ -1132,7 +1148,8 @@ Layer*
FrameLayerBuilder::GetOldLayerFor(nsDisplayItem* aItem,
nsDisplayItemGeometry** aOldGeometry,
Clip** aOldClip,
nsTArray<nsIFrame*>* aChangedFrames)
nsTArray<nsIFrame*>* aChangedFrames,
bool *aIsInvalid)
{
uint32_t key = aItem->GetPerFrameKey();
nsIFrame* frame = aItem->GetUnderlyingFrame();
@ -1149,6 +1166,9 @@ FrameLayerBuilder::GetOldLayerFor(nsDisplayItem* aItem,
if (aChangedFrames) {
oldData->GetFrameListChanges(aItem, *aChangedFrames);
}
if (aIsInvalid) {
*aIsInvalid = oldData->mIsInvalid;
}
return oldData->mLayer;
}
}
@ -2196,7 +2216,8 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
nsDisplayItemGeometry *oldGeometry = NULL;
FrameLayerBuilder::Clip* oldClip = NULL;
nsAutoTArray<nsIFrame*,4> changedFrames;
Layer* oldLayer = mLayerBuilder->GetOldLayerFor(aItem, &oldGeometry, &oldClip, &changedFrames);
bool isInvalid = false;
Layer* oldLayer = mLayerBuilder->GetOldLayerFor(aItem, &oldGeometry, &oldClip, &changedFrames, &isInvalid);
if (aNewLayer != oldLayer && oldLayer) {
// The item has changed layers.
// Invalidate the old bounds in the old layer and new bounds in the new layer.
@ -2248,7 +2269,7 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
#ifdef DEBUG_INVALIDATIONS
printf("Display item type %s(%p) added to layer %p!\n", aItem->Name(), aItem->GetUnderlyingFrame(), aNewLayer);
#endif
} else if (aItem->IsInvalid(invalid) && invalid.IsEmpty()) {
} else if (isInvalid || (aItem->IsInvalid(invalid) && invalid.IsEmpty())) {
// Either layout marked item as needing repainting, invalidate the entire old and new areas.
combined = oldClip->ApplyNonRoundedIntersection(oldGeometry->ComputeInvalidationRegion());
combined.MoveBy(shift);

View File

@ -300,7 +300,8 @@ public:
Layer* GetOldLayerFor(nsDisplayItem* aItem,
nsDisplayItemGeometry** aOldGeometry = nullptr,
Clip** aOldClip = nullptr,
nsTArray<nsIFrame*>* aChangedFrames = nullptr);
nsTArray<nsIFrame*>* aChangedFrames = nullptr,
bool *aIsInvalid = nullptr);
static Layer* GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey);
@ -336,6 +337,11 @@ 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);
/**
* Save transform that was in aLayer when we last painted, and the position
* of the active scrolled root frame. It must be an integer
@ -466,7 +472,6 @@ public:
NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(LayerManagerDataProperty,
RemoveFrameFromLayerManager)
protected:
/**
* Retained data storage:
*
@ -485,6 +490,12 @@ protected:
*/
class DisplayItemData {
public:
friend class FrameLayerBuilder;
uint32_t GetDisplayItemKey() { return mDisplayItemKey; }
Layer* GetLayer() { return mLayer; }
void Invalidate() { mIsInvalid = true; }
protected:
DisplayItemData(LayerManagerData* aParent, uint32_t aKey, Layer* aLayer, LayerState aLayerState, uint32_t aGeneration);
DisplayItemData(DisplayItemData &toCopy);
@ -497,6 +508,7 @@ protected:
NS_INLINE_DECL_REFCOUNTING(DisplayItemData)
/**
* Associates this DisplayItemData with a frame, and adds it
* to the LayerManagerDataProperty list on the frame.
@ -531,8 +543,11 @@ protected:
* paint) has been updated in the current paint.
*/
bool mUsed;
bool mIsInvalid;
};
protected:
friend class LayerManagerData;
static void RemoveFrameFromLayerManager(nsIFrame* aFrame, void* aPropertyValue);

View File

@ -18,8 +18,10 @@ enum Type {
TYPE_ZERO = 0, /** Spacer so that the first item starts at 1 */
#define DECLARE_DISPLAY_ITEM_TYPE(name) TYPE_##name,
#define DECLARE_DISPLAY_ITEM_TYPE_FLAGS(name,flags) TYPE_##name,
#include "nsDisplayItemTypesList.h"
#undef DECLARE_DISPLAY_ITEM_TYPE
#undef DECLARE_DISPLAY_ITEM_TYPE_FLAGS
TYPE_MAX
};
@ -29,13 +31,41 @@ enum {
TYPE_BITS = 8
};
enum DisplayItemFlags {
TYPE_RENDERS_NO_IMAGES = 1 << 0
};
static const char* DisplayItemTypeName(Type aType)
{
switch (aType) {
#define DECLARE_DISPLAY_ITEM_TYPE(name) case TYPE_##name: return #name;
#define DECLARE_DISPLAY_ITEM_TYPE_FLAGS(name,flags) case TYPE_##name: return #name;
#include "nsDisplayItemTypesList.h"
#undef DECLARE_DISPLAY_ITEM_TYPE
#undef DECLARE_DISPLAY_ITEM_TYPE_FLAGS
default: return "TYPE_UNKNOWN";
}
}
static uint8_t GetDisplayItemFlagsForType(Type aType)
{
static const uint8_t flags[TYPE_MAX] = {
0
#define DECLARE_DISPLAY_ITEM_TYPE(name) ,0
#define DECLARE_DISPLAY_ITEM_TYPE_FLAGS(name,flags) ,flags
#include "nsDisplayItemTypesList.h"
#undef DECLARE_DISPLAY_ITEM_TYPE
#undef DECLARE_DISPLAY_ITEM_TYPE_FLAGS
};
return flags[aType];
}
static Type GetDisplayItemTypeFromKey(uint32_t aDisplayItemKey)
{
static const uint32_t typeMask = (1 << TYPE_BITS) - 1;
Type type = static_cast<Type>(aDisplayItemKey & typeMask);
NS_ASSERTION(type > TYPE_ZERO && type < TYPE_MAX, "Invalid display item type!");
return type;
}

View File

@ -1,6 +1,6 @@
DECLARE_DISPLAY_ITEM_TYPE(ALT_FEEDBACK)
DECLARE_DISPLAY_ITEM_TYPE(BACKGROUND)
DECLARE_DISPLAY_ITEM_TYPE(BACKGROUND_COLOR)
DECLARE_DISPLAY_ITEM_TYPE_FLAGS(BACKGROUND_COLOR,TYPE_RENDERS_NO_IMAGES)
DECLARE_DISPLAY_ITEM_TYPE(BORDER)
DECLARE_DISPLAY_ITEM_TYPE(BOX_SHADOW_OUTER)
DECLARE_DISPLAY_ITEM_TYPE(BOX_SHADOW_INNER)

View File

@ -10,6 +10,8 @@
#include "nsContentUtils.h"
#include "nsLayoutUtils.h"
#include "nsError.h"
#include "nsDisplayList.h"
#include "FrameLayerBuilder.h"
namespace mozilla {
namespace css {
@ -314,6 +316,20 @@ ImageLoader::GetPresContext()
return shell->GetPresContext();
}
void InvalidateImagesCallback(nsIFrame* aFrame,
FrameLayerBuilder::DisplayItemData* aItem)
{
nsDisplayItem::Type type = nsDisplayItem::GetDisplayItemTypeFromKey(aItem->GetDisplayItemKey());
uint8_t flags = nsDisplayItem::GetDisplayItemFlagsForType(type);
if (flags & nsDisplayItem::TYPE_RENDERS_NO_IMAGES) {
return;
}
aItem->Invalidate();
aFrame->SchedulePaint();
}
void
ImageLoader::DoRedraw(FrameSet* aFrameSet)
{
@ -325,7 +341,7 @@ ImageLoader::DoRedraw(FrameSet* aFrameSet)
nsIFrame* frame = aFrameSet->ElementAt(i);
if (frame->GetStyleVisibility()->IsVisible()) {
frame->InvalidateFrame();
FrameLayerBuilder::IterateRetainedDataFor(frame, InvalidateImagesCallback);
}
}
}