Bug 539356 - Part 28 - Cached nsDisplayBackground rasterizations with BasicLayers. r=roc

This commit is contained in:
Matt Woodrow 2012-06-30 15:06:14 +12:00
Родитель 07c0b565fc
Коммит 3daa95107f
6 изменённых файлов: 137 добавлений и 4 удалений

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

@ -818,6 +818,7 @@ FrameLayerBuilder::ProcessRemovedDisplayItems(DisplayItemDataEntry* aEntry,
item.mGeometry->ComputeInvalidationRegion(). item.mGeometry->ComputeInvalidationRegion().
ScaleToOutsidePixels(data->mXScale, data->mYScale, item.mGeometry->mAppUnitsPerDevPixel), ScaleToOutsidePixels(data->mXScale, data->mYScale, item.mGeometry->mAppUnitsPerDevPixel),
item.mGeometry->mPaintOffset); item.mGeometry->mPaintOffset);
aEntry->GetKey()->ClearDisplayItemCache();
} }
} }
@ -2003,6 +2004,7 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem, Layer* aNewLayer,
GetTranslationForThebesLayer(newThebesLayer)); GetTranslationForThebesLayer(newThebesLayer));
} }
} }
aItem->GetUnderlyingFrame()->ClearDisplayItemCache();
return; return;
} }
if (!aNewLayer) { if (!aNewLayer) {
@ -2057,6 +2059,7 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem, Layer* aNewLayer,
InvalidatePostTransformRegion(newThebesLayer, InvalidatePostTransformRegion(newThebesLayer,
combined.ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel), combined.ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
GetTranslationForThebesLayer(newThebesLayer)); GetTranslationForThebesLayer(newThebesLayer));
aItem->GetUnderlyingFrame()->ClearDisplayItemCache();
} }
} }
@ -2892,7 +2895,9 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
} }
if (cdi->mInactiveLayer) { if (cdi->mInactiveLayer) {
builder->SetIsCompositingCheap(false);
PaintInactiveLayer(builder, cdi->mInactiveLayer, cdi->mItem, aContext, rc); PaintInactiveLayer(builder, cdi->mInactiveLayer, cdi->mItem, aContext, rc);
builder->SetIsCompositingCheap(aLayer->Manager()->IsCompositingCheap());
} else { } else {
nsIFrame* frame = cdi->mItem->GetUnderlyingFrame(); nsIFrame* frame = cdi->mItem->GetUnderlyingFrame();
if (frame) { if (frame) {

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

@ -65,7 +65,8 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
mSyncDecodeImages(false), mSyncDecodeImages(false),
mIsPaintingToWindow(false), mIsPaintingToWindow(false),
mHasDisplayPort(false), mHasDisplayPort(false),
mHasFixedItems(false) mHasFixedItems(false),
mIsCompositingCheap(false)
{ {
MOZ_COUNT_CTOR(nsDisplayListBuilder); MOZ_COUNT_CTOR(nsDisplayListBuilder);
PL_InitArenaPool(&mPool, "displayListArena", 1024, PL_InitArenaPool(&mPool, "displayListArena", 1024,
@ -668,6 +669,7 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
layerManager->SetRoot(root); layerManager->SetRoot(root);
layerBuilder->WillEndTransaction(); layerBuilder->WillEndTransaction();
aBuilder->SetIsCompositingCheap(layerManager->IsCompositingCheap());
layerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer, layerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer,
aBuilder, (aFlags & PAINT_NO_COMPOSITE) ? LayerManager::END_NO_COMPOSITE : LayerManager::END_DEFAULT); aBuilder, (aFlags & PAINT_NO_COMPOSITE) ? LayerManager::END_NO_COMPOSITE : LayerManager::END_DEFAULT);
layerBuilder->DidEndTransaction(); layerBuilder->DidEndTransaction();
@ -1132,6 +1134,65 @@ static bool RoundedRectContainsRect(const nsRect& aRoundedRect,
return rgn.Contains(aContainedRect); return rgn.Contains(aContainedRect);
} }
bool
nsDisplayBackground::IsSingleFixedPositionImage(nsDisplayListBuilder* aBuilder, const nsRect& aClipRect)
{
if (mIsThemed)
return false;
nsPresContext* presContext = mFrame->PresContext();
nsStyleContext* bgSC;
if (!nsCSSRendering::FindBackground(presContext, mFrame, &bgSC))
return false;
bool drawBackgroundImage;
bool drawBackgroundColor;
nsCSSRendering::DetermineBackgroundColor(presContext,
bgSC,
mFrame,
drawBackgroundImage,
drawBackgroundColor);
// For now we don't know how to draw image layers with a background color.
if (!drawBackgroundImage || drawBackgroundColor)
return false;
const nsStyleBackground *bg = bgSC->GetStyleBackground();
// We could pretty easily support multiple image layers, but for now we
// just punt here.
if (bg->mLayers.Length() != 1)
return false;
PRUint32 flags = aBuilder->GetBackgroundPaintFlags();
nsPoint offset = ToReferenceFrame();
nsRect borderArea = nsRect(offset, mFrame->GetSize());
const nsStyleBackground::Layer &layer = bg->mLayers[0];
if (layer.mAttachment != NS_STYLE_BG_ATTACHMENT_FIXED)
return false;
nsBackgroundLayerState state =
nsCSSRendering::PrepareBackgroundLayer(presContext,
mFrame,
flags,
borderArea,
aClipRect,
*bg,
layer);
nsImageRenderer* imageRenderer = &state.mImageRenderer;
// We only care about images here, not gradients.
if (!imageRenderer->IsRasterImage())
return false;
PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
mDestRect = nsLayoutUtils::RectToGfxRect(state.mFillArea, appUnitsPerDevPixel);
return true;
}
bool bool
nsDisplayBackground::TryOptimizeToImageLayer(nsDisplayListBuilder* aBuilder) nsDisplayBackground::TryOptimizeToImageLayer(nsDisplayListBuilder* aBuilder)
{ {
@ -1528,6 +1589,7 @@ nsDisplayBackground::ShouldFixToViewport(nsDisplayListBuilder* aBuilder)
void void
nsDisplayBackground::Paint(nsDisplayListBuilder* aBuilder, nsDisplayBackground::Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx) { nsRenderingContext* aCtx) {
nsPoint offset = ToReferenceFrame(); nsPoint offset = ToReferenceFrame();
PRUint32 flags = aBuilder->GetBackgroundPaintFlags(); PRUint32 flags = aBuilder->GetBackgroundPaintFlags();
nsDisplayItem* nextItem = GetAbove(); nsDisplayItem* nextItem = GetAbove();

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

@ -224,6 +224,9 @@ public:
*/ */
void SetPaintingToWindow(bool aToWindow) { mIsPaintingToWindow = aToWindow; } void SetPaintingToWindow(bool aToWindow) { mIsPaintingToWindow = aToWindow; }
bool IsPaintingToWindow() const { return mIsPaintingToWindow; } bool IsPaintingToWindow() const { return mIsPaintingToWindow; }
void SetIsCompositingCheap(bool aCompositingCheap) { mIsCompositingCheap = aCompositingCheap; }
bool IsCompositingCheap() const { return mIsCompositingCheap; }
/** /**
* Display the caret if needed. * Display the caret if needed.
*/ */
@ -532,6 +535,7 @@ private:
bool mIsPaintingToWindow; bool mIsPaintingToWindow;
bool mHasDisplayPort; bool mHasDisplayPort;
bool mHasFixedItems; bool mHasFixedItems;
bool mIsCompositingCheap;
}; };
class nsDisplayItem; class nsDisplayItem;
@ -1703,6 +1707,7 @@ protected:
const nsRect& aRect, bool* aSnap); const nsRect& aRect, bool* aSnap);
bool TryOptimizeToImageLayer(nsDisplayListBuilder* aBuilder); bool TryOptimizeToImageLayer(nsDisplayListBuilder* aBuilder);
bool IsSingleFixedPositionImage(nsDisplayListBuilder* aBuilder, const nsRect& aClipRect);
void ConfigureLayer(ImageLayer* aLayer); void ConfigureLayer(ImageLayer* aLayer);
/* Used to cache mFrame->IsThemed() since it isn't a cheap call */ /* Used to cache mFrame->IsThemed() since it isn't a cheap call */

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

@ -179,6 +179,16 @@ nsRect nsCanvasFrame::CanvasArea() const
return result; return result;
} }
static void BlitSurface(gfxContext* aDest, const gfxRect& aRect, gfxASurface* aSource)
{
aDest->Translate(gfxPoint(aRect.x, aRect.y));
aDest->SetSource(aSource);
aDest->NewPath();
aDest->Rectangle(gfxRect(0, 0, aRect.width, aRect.height));
aDest->Fill();
aDest->Translate(-gfxPoint(aRect.x, aRect.y));
}
void void
nsDisplayCanvasBackground::Paint(nsDisplayListBuilder* aBuilder, nsDisplayCanvasBackground::Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx) nsRenderingContext* aCtx)
@ -186,17 +196,46 @@ nsDisplayCanvasBackground::Paint(nsDisplayListBuilder* aBuilder,
nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame); nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
nsPoint offset = ToReferenceFrame(); nsPoint offset = ToReferenceFrame();
nsRect bgClipRect = frame->CanvasArea() + offset; nsRect bgClipRect = frame->CanvasArea() + offset;
if (NS_GET_A(mExtraBackgroundColor) > 0) { if (NS_GET_A(mExtraBackgroundColor) > 0) {
aCtx->SetColor(mExtraBackgroundColor); aCtx->SetColor(mExtraBackgroundColor);
aCtx->FillRect(bgClipRect); aCtx->FillRect(bgClipRect);
} }
nsCSSRendering::PaintBackground(mFrame->PresContext(), *aCtx, mFrame, bool snap;
mVisibleRect, nsRect bounds = GetBounds(aBuilder, &snap);
nsIntRect pixelRect = bounds.ToOutsidePixels(mFrame->PresContext()->AppUnitsPerDevPixel());
nsRenderingContext context;
nsRefPtr<gfxContext> dest = aCtx->ThebesContext();
nsRefPtr<gfxASurface> surf;
nsRefPtr<gfxContext> ctx;
#ifndef MOZ_GFX_OPTIMIZE_MOBILE
if (IsSingleFixedPositionImage(aBuilder, bgClipRect) && aBuilder->IsPaintingToWindow() && !aBuilder->IsCompositingCheap()) {
surf = static_cast<gfxASurface*>(GetUnderlyingFrame()->Properties().Get(nsIFrame::CachedBackgroundImage()));
nsRefPtr<gfxASurface> destSurf = dest->CurrentSurface();
if (surf && surf->GetType() == destSurf->GetType()) {
BlitSurface(dest, mDestRect, surf);
return;
}
surf = destSurf->CreateSimilarSurface(gfxASurface::CONTENT_COLOR_ALPHA, gfxIntSize(ceil(mDestRect.width), ceil(mDestRect.height)));
if (surf) {
ctx = new gfxContext(surf);
ctx->Translate(-gfxPoint(mDestRect.x, mDestRect.y));
context.Init(aCtx->DeviceContext(), ctx);
}
}
#endif
nsCSSRendering::PaintBackground(mFrame->PresContext(), surf ? context : *aCtx, mFrame,
surf ? bounds : mVisibleRect,
nsRect(offset, mFrame->GetSize()), nsRect(offset, mFrame->GetSize()),
aBuilder->GetBackgroundPaintFlags(), aBuilder->GetBackgroundPaintFlags(),
&bgClipRect); &bgClipRect);
if (surf) {
BlitSurface(dest, mDestRect, surf);
GetUnderlyingFrame()->Properties().Set(nsIFrame::CachedBackgroundImage(), surf.forget().get());
GetUnderlyingFrame()->AddStateBits(NS_FRAME_HAS_CACHED_BACKGROUND);
}
} }
/** /**

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

@ -253,6 +253,15 @@ nsIFrame::MarkAsAbsoluteContainingBlock() {
Properties().Set(AbsoluteContainingBlockProperty(), new nsAbsoluteContainingBlock(GetAbsoluteListID())); Properties().Set(AbsoluteContainingBlockProperty(), new nsAbsoluteContainingBlock(GetAbsoluteListID()));
} }
void
nsIFrame::ClearDisplayItemCache()
{
if (HasAnyStateBits(NS_FRAME_HAS_CACHED_BACKGROUND)) {
Properties().Delete(CachedBackgroundImage());
RemoveStateBits(NS_FRAME_HAS_CACHED_BACKGROUND);
}
}
bool bool
nsIFrame::CheckAndClearPaintedState() nsIFrame::CheckAndClearPaintedState()
{ {

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

@ -295,6 +295,10 @@ typedef PRUint64 nsFrameState;
// Frame is a descendant of a popup // Frame is a descendant of a popup
#define NS_FRAME_IN_POPUP NS_FRAME_STATE_BIT(48) #define NS_FRAME_IN_POPUP NS_FRAME_STATE_BIT(48)
// Frame has a cached rasterization of anV
// nsDisplayBackground display item
#define NS_FRAME_HAS_CACHED_BACKGROUND NS_FRAME_STATE_BIT(49)
// Box layout bits // Box layout bits
#define NS_STATE_IS_HORIZONTAL NS_FRAME_STATE_BIT(22) #define NS_STATE_IS_HORIZONTAL NS_FRAME_STATE_BIT(22)
#define NS_STATE_IS_DIRECTION_NORMAL NS_FRAME_STATE_BIT(31) #define NS_STATE_IS_DIRECTION_NORMAL NS_FRAME_STATE_BIT(31)
@ -875,6 +879,11 @@ public:
delete static_cast<nsOverflowAreas*>(aPropertyValue); delete static_cast<nsOverflowAreas*>(aPropertyValue);
} }
static void DestroySurface(void* aPropertyValue)
{
static_cast<gfxASurface*>(aPropertyValue)->Release();
}
#ifdef _MSC_VER #ifdef _MSC_VER
// XXX Workaround MSVC issue by making the static FramePropertyDescriptor // XXX Workaround MSVC issue by making the static FramePropertyDescriptor
// non-const. See bug 555727. // non-const. See bug 555727.
@ -918,6 +927,8 @@ public:
NS_DECLARE_FRAME_PROPERTY(LineBaselineOffset, nsnull) NS_DECLARE_FRAME_PROPERTY(LineBaselineOffset, nsnull)
NS_DECLARE_FRAME_PROPERTY(CachedBackgroundImage, DestroySurface)
/** /**
* Return the distance between the border edge of the frame and the * Return the distance between the border edge of the frame and the
* margin edge of the frame. Like GetRect(), returns the dimensions * margin edge of the frame. Like GetRect(), returns the dimensions
@ -2547,6 +2558,8 @@ NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::ParagraphDepthProperty()))
*/ */
virtual bool IsFocusable(PRInt32 *aTabIndex = nsnull, bool aWithMouse = false); virtual bool IsFocusable(PRInt32 *aTabIndex = nsnull, bool aWithMouse = false);
void ClearDisplayItemCache();
// BOX LAYOUT METHODS // BOX LAYOUT METHODS
// These methods have been migrated from nsIBox and are in the process of // These methods have been migrated from nsIBox and are in the process of
// being refactored. DO NOT USE OUTSIDE OF XUL. // being refactored. DO NOT USE OUTSIDE OF XUL.