Bug 564991. Part 13: Optimize invalidation to avoid repainting ThebesLayer contents sometimes. r=mats,sr=dbaron

This commit is contained in:
Robert O'Callahan 2010-07-16 09:07:53 +12:00
Родитель 4b1b78c893
Коммит 2e3d02e038
10 изменённых файлов: 80 добавлений и 13 удалений

Просмотреть файл

@ -46,6 +46,7 @@
#include "jsapi.h"
#include "nsFrameManager.h"
#include "nsDisplayList.h"
#include "ImageLayers.h"
#include "BasicLayers.h"
@ -502,10 +503,10 @@ nsHTMLCanvasElement::InvalidateFrame(const gfxRect* damageRect)
// account for border/padding
invalRect.MoveBy(contentArea.TopLeft() - frame->GetPosition());
frame->Invalidate(invalRect);
frame->InvalidateLayer(invalRect, nsDisplayItem::TYPE_CANVAS);
} else {
nsRect r(frame->GetContentRect() - frame->GetPosition());
frame->Invalidate(r);
frame->InvalidateLayer(r, nsDisplayItem::TYPE_CANVAS);
}
}

Просмотреть файл

@ -52,6 +52,7 @@
#include "gfxImageSurface.h"
#include "nsPresContext.h"
#include "nsDOMError.h"
#include "nsDisplayList.h"
#if defined(XP_MACOSX)
#include "gfxQuartzImageSurface.h"
@ -149,8 +150,9 @@ void nsMediaDecoder::Invalidate()
}
if (frame) {
nsRect r(nsPoint(0,0), frame->GetSize());
frame->Invalidate(r);
nsRect contentRect = frame->GetContentRect() - frame->GetPosition();
// Only the layer needs to be updated here
frame->InvalidateLayer(contentRect, nsDisplayItem::TYPE_VIDEO);
}
}

Просмотреть файл

@ -1004,6 +1004,27 @@ FrameLayerBuilder::InvalidateAllLayers(LayerManager* aManager)
}
}
/* static */
PRBool
FrameLayerBuilder::HasDedicatedLayer(nsIFrame* aFrame, PRUint32 aDisplayItemKey)
{
void* propValue = aFrame->Properties().Get(DisplayItemDataProperty());
if (!propValue)
return PR_FALSE;
nsTArray<DisplayItemData>* array =
(reinterpret_cast<nsTArray<DisplayItemData>*>(&propValue));
for (PRUint32 i = 0; i < array->Length(); ++i) {
if (array->ElementAt(i).mDisplayItemKey == aDisplayItemKey) {
void* layerUserData = array->ElementAt(i).mLayer->GetUserData();
if (layerUserData != &gColorLayerUserData &&
layerUserData != &gThebesDisplayItemLayerUserData)
return PR_TRUE;
}
}
return PR_FALSE;
}
/* static */ void
FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
gfxContext* aContext,

Просмотреть файл

@ -170,7 +170,13 @@ public:
* the next paint.
*/
static void InvalidateAllLayers(LayerManager* aManager);
/**
* Call this to determine if a frame has a dedicated (non-Thebes) layer
* for the given display item key.
*/
static PRBool HasDedicatedLayer(nsIFrame* aFrame, PRUint32 aDisplayItemKey);
/**
* This callback must be provided to EndTransaction. The callback data
* must be the nsDisplayListBuilder containing this FrameLayerBuilder.

Просмотреть файл

@ -7670,6 +7670,10 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame,
aFrame->InvalidateOverflowRect();
}
}
if (aChange & nsChangeHint_UpdateOpacityLayer) {
aFrame->InvalidateLayer(aFrame->GetOverflowRectRelativeToSelf(),
nsDisplayItem::TYPE_OPACITY);
}
}
}
@ -7952,7 +7956,8 @@ nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
StyleChangeReflow(frame, hint);
didReflow = PR_TRUE;
}
if (hint & (nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView)) {
if (hint & (nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView |
nsChangeHint_UpdateOpacityLayer)) {
ApplyRenderingChangeToTree(presContext, frame, hint);
didInvalidate = PR_TRUE;
}

Просмотреть файл

@ -82,9 +82,15 @@ enum nsChangeHint {
*/
nsChangeHint_UpdateEffects = 0x80,
/**
* Visual change only, but the change can be handled entirely by
* updating the layer(s) for the frame.
*/
nsChangeHint_UpdateOpacityLayer = 0x100,
// change requires frame change (e.g., display:).
// This subsumes all the above.
nsChangeHint_ReconstructFrame = 0x100
nsChangeHint_ReconstructFrame = 0x200
};
// Redefine these operators to return nothing. This will catch any use

Просмотреть файл

@ -3679,6 +3679,19 @@ nsIFrame::IsLeaf() const
return PR_TRUE;
}
void
nsIFrame::InvalidateLayer(const nsRect& aDamageRect, PRUint32 aDisplayItemKey)
{
NS_ASSERTION(aDisplayItemKey > 0, "Need a key");
if (!FrameLayerBuilder::HasDedicatedLayer(this, aDisplayItemKey)) {
Invalidate(aDamageRect);
return;
}
InvalidateWithFlags(aDamageRect, INVALIDATE_NO_THEBES_LAYERS);
}
void
nsIFrame::InvalidateWithFlags(const nsRect& aDamageRect, PRUint32 aFlags)
{

Просмотреть файл

@ -1835,6 +1835,15 @@ public:
void Invalidate(const nsRect& aDamageRect)
{ return InvalidateWithFlags(aDamageRect, 0); }
/**
* As Invalidate above, except that this should be called when the
* rendering that has changed is performed using layers so we can avoid
* updating the contents of ThebesLayers.
* @param aDisplayItemKey must not be zero; indicates the kind of display
* item that is being invalidated.
*/
void InvalidateLayer(const nsRect& aDamageRect, PRUint32 aDisplayItemKey);
/**
* Helper function that can be overridden by frame classes. The rectangle
* (plus aOffsetX/aOffsetY) is relative to this frame.

Просмотреть файл

@ -412,9 +412,6 @@ nsStyleContext::CalcStyleDifference(nsStyleContext* aOther)
// our position in the rule node tree is also the same.
PRBool compare = mRuleNode != aOther->mRuleNode;
nsChangeHint maxHint = nsChangeHint(NS_STYLE_HINT_FRAMECHANGE |
nsChangeHint_UpdateCursor);
#define DO_STRUCT_DIFFERENCE(struct_) \
PR_BEGIN_MACRO \
NS_ASSERTION(NS_IsHintSubset(nsStyle##struct_::MaxDifference(), maxHint), \
@ -438,7 +435,12 @@ nsStyleContext::CalcStyleDifference(nsStyleContext* aOther)
// causing the maximal difference, a FRAMECHANGE.
// FRAMECHANGE Structs: Display, XUL, Content, UserInterface,
// Visibility, Outline, TableBorder, Table, Text, UIReset, Quotes
nsChangeHint maxHint = nsChangeHint(NS_STYLE_HINT_FRAMECHANGE |
nsChangeHint_UpdateOpacityLayer);
DO_STRUCT_DIFFERENCE(Display);
maxHint = nsChangeHint(NS_STYLE_HINT_FRAMECHANGE |
nsChangeHint_UpdateCursor);
DO_STRUCT_DIFFERENCE(XUL);
DO_STRUCT_DIFFERENCE(Column);
DO_STRUCT_DIFFERENCE(Content);

Просмотреть файл

@ -1890,8 +1890,9 @@ nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const
|| mAppearance != aOther.mAppearance)
NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_ReflowFrame, nsChangeHint_RepaintFrame));
if (mOpacity != aOther.mOpacity)
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
if (mOpacity != aOther.mOpacity) {
NS_UpdateHint(hint, nsChangeHint_UpdateOpacityLayer);
}
/* If we've added or removed the transform property, we need to reconstruct the frame to add
* or remove the view object, and also to handle abs-pos and fixed-pos containers.
@ -1936,7 +1937,8 @@ nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const
nsChangeHint nsStyleDisplay::MaxDifference()
{
// All the parts of FRAMECHANGE are present above in CalcDifference.
return NS_STYLE_HINT_FRAMECHANGE;
return nsChangeHint(NS_STYLE_HINT_FRAMECHANGE |
nsChangeHint_UpdateOpacityLayer);
}
#endif