Bug 781053 - Part 2 - Trigger empty transactions when an animated image in an ImageLayer changes frame. r=roc

This commit is contained in:
Matt Woodrow 2012-09-25 08:31:30 +12:00
Родитель af81361caa
Коммит 53908eb696
6 изменённых файлов: 101 добавлений и 29 удалений

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

@ -171,7 +171,8 @@ RasterImage::RasterImage(imgStatusTracker* aStatusTracker) :
mHasBeenDecoded(false), mHasBeenDecoded(false),
mInDecoder(false), mInDecoder(false),
mAnimationFinished(false), mAnimationFinished(false),
mFinishing(false) mFinishing(false),
mInUpdateImageContainer(false)
{ {
// Set up the discard tracker node. // Set up the discard tracker node.
mDiscardTrackerNode.img = this; mDiscardTrackerNode.img = this;
@ -292,7 +293,6 @@ RasterImage::AdvanceFrame(TimeStamp aTime, nsIntRect* aDirtyRect)
uint32_t currentFrameIndex = mAnim->currentAnimationFrameIndex; uint32_t currentFrameIndex = mAnim->currentAnimationFrameIndex;
uint32_t nextFrameIndex = mAnim->currentAnimationFrameIndex + 1; uint32_t nextFrameIndex = mAnim->currentAnimationFrameIndex + 1;
uint32_t timeout = 0; uint32_t timeout = 0;
mImageContainer = nullptr;
// Figure out if we have the next full frame. This is more complicated than // Figure out if we have the next full frame. This is more complicated than
// just checking for mFrames.Length() because decoders append their frames // just checking for mFrames.Length() because decoders append their frames
@ -439,6 +439,7 @@ RasterImage::RequestRefresh(const mozilla::TimeStamp& aTime)
mFramesNotified++; mFramesNotified++;
#endif #endif
UpdateImageContainer();
observer->FrameChanged(nullptr, this, &dirtyRect); observer->FrameChanged(nullptr, this, &dirtyRect);
} }
} }
@ -862,6 +863,28 @@ RasterImage::GetFrame(uint32_t aWhichFrame,
return rv; return rv;
} }
already_AddRefed<layers::Image>
RasterImage::GetCurrentImage()
{
nsRefPtr<gfxASurface> imageSurface;
nsresult rv = GetFrame(FRAME_CURRENT, FLAG_SYNC_DECODE, getter_AddRefs(imageSurface));
NS_ENSURE_SUCCESS(rv, nullptr);
CairoImage::Data cairoData;
cairoData.mSurface = imageSurface;
GetWidth(&cairoData.mSize.width);
GetHeight(&cairoData.mSize.height);
ImageFormat cairoFormat = CAIRO_SURFACE;
nsRefPtr<layers::Image> image = mImageContainer->CreateImage(&cairoFormat, 1);
NS_ASSERTION(image, "Failed to create Image");
NS_ASSERTION(image->GetFormat() == cairoFormat, "Wrong format");
static_cast<CairoImage*>(image.get())->SetData(cairoData);
return image.forget();
}
NS_IMETHODIMP NS_IMETHODIMP
RasterImage::GetImageContainer(ImageContainer **_retval) RasterImage::GetImageContainer(ImageContainer **_retval)
@ -872,24 +895,12 @@ RasterImage::GetImageContainer(ImageContainer **_retval)
return NS_OK; return NS_OK;
} }
CairoImage::Data cairoData;
nsRefPtr<gfxASurface> imageSurface;
nsresult rv = GetFrame(FRAME_CURRENT, FLAG_SYNC_DECODE, getter_AddRefs(imageSurface));
NS_ENSURE_SUCCESS(rv, rv);
cairoData.mSurface = imageSurface;
GetWidth(&cairoData.mSize.width);
GetHeight(&cairoData.mSize.height);
mImageContainer = LayerManager::CreateImageContainer(); mImageContainer = LayerManager::CreateImageContainer();
// Now create a CairoImage to display the surface. nsRefPtr<layers::Image> image = GetCurrentImage();
ImageFormat cairoFormat = CAIRO_SURFACE; if (!image) {
nsRefPtr<layers::Image> image = mImageContainer->CreateImage(&cairoFormat, 1); return NS_ERROR_FAILURE;
NS_ASSERTION(image, "Failed to create Image"); }
NS_ASSERTION(image->GetFormat() == cairoFormat, "Wrong format");
static_cast<CairoImage*>(image.get())->SetData(cairoData);
mImageContainer->SetCurrentImageInTransaction(image); mImageContainer->SetCurrentImageInTransaction(image);
*_retval = mImageContainer; *_retval = mImageContainer;
@ -897,6 +908,23 @@ RasterImage::GetImageContainer(ImageContainer **_retval)
return NS_OK; return NS_OK;
} }
void
RasterImage::UpdateImageContainer()
{
if (!mImageContainer || IsInUpdateImageContainer()) {
return;
}
SetInUpdateImageContainer(true);
nsRefPtr<layers::Image> image = GetCurrentImage();
if (!image) {
return;
}
mImageContainer->SetCurrentImage(image);
SetInUpdateImageContainer(false);
}
size_t size_t
RasterImage::HeapSizeOfSourceWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const RasterImage::HeapSizeOfSourceWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const
{ {
@ -1185,8 +1213,11 @@ RasterImage::FrameUpdated(uint32_t aFrameNum, nsIntRect &aUpdatedRect)
NS_ABORT_IF_FALSE(frame, "Calling FrameUpdated on frame that doesn't exist!"); NS_ABORT_IF_FALSE(frame, "Calling FrameUpdated on frame that doesn't exist!");
frame->ImageUpdated(aUpdatedRect); frame->ImageUpdated(aUpdatedRect);
// The image has changed, so we need to invalidate our cached ImageContainer.
mImageContainer = NULL; if (aFrameNum == GetCurrentImgFrameIndex()) {
// The image has changed, so we need to invalidate our cached ImageContainer.
UpdateImageContainer();
}
} }
nsresult nsresult
@ -1380,7 +1411,7 @@ RasterImage::ResetAnimation()
mAnim->lastCompositedFrameIndex = -1; mAnim->lastCompositedFrameIndex = -1;
mAnim->currentAnimationFrameIndex = 0; mAnim->currentAnimationFrameIndex = 0;
mImageContainer = nullptr; UpdateImageContainer();
// Note - We probably want to kick off a redecode somewhere around here when // Note - We probably want to kick off a redecode somewhere around here when
// we fix bug 500402. // we fix bug 500402.

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

@ -127,6 +127,7 @@ namespace mozilla {
namespace layers { namespace layers {
class LayerManager; class LayerManager;
class ImageContainer; class ImageContainer;
class Image;
} }
namespace image { namespace image {
@ -574,6 +575,12 @@ private:
bool ApplyDecodeFlags(uint32_t aNewFlags); bool ApplyDecodeFlags(uint32_t aNewFlags);
already_AddRefed<layers::Image> GetCurrentImage();
void UpdateImageContainer();
void SetInUpdateImageContainer(bool aInUpdate) { mInUpdateImageContainer = aInUpdate; }
bool IsInUpdateImageContainer() { return mInUpdateImageContainer; }
private: // data private: // data
nsIntSize mSize; nsIntSize mSize;
@ -654,6 +661,8 @@ private: // data
// Whether we're calling Decoder::Finish() from ShutdownDecoder. // Whether we're calling Decoder::Finish() from ShutdownDecoder.
bool mFinishing:1; bool mFinishing:1;
bool mInUpdateImageContainer:1;
// Decoding // Decoding
nsresult WantDecodedFrames(); nsresult WantDecodedFrames();
nsresult SyncDecode(); nsresult SyncDecode();

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

@ -874,6 +874,25 @@ FrameLayerBuilder::DidBeginRetainedLayerTransaction(LayerManager* aManager)
} }
} }
void
FrameLayerBuilder::StoreOptimizedLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey, Layer* aImage)
{
DisplayItemDataEntry *entry = mNewDisplayItemData.GetEntry(aFrame);
if (!entry)
return;
nsTArray<nsRefPtr<DisplayItemData> > *array = &entry->mData;
if (!array)
return;
for (uint32_t i = 0; i < array->Length(); ++i) {
if (array->ElementAt(i)->mDisplayItemKey == aDisplayItemKey) {
array->ElementAt(i)->mOptLayer = aImage;
return;
}
}
}
void void
FrameLayerBuilder::DidEndTransaction() FrameLayerBuilder::DidEndTransaction()
{ {
@ -1610,6 +1629,9 @@ ContainerState::PopThebesLayerData()
imageLayer->IntersectClipRect(clip); imageLayer->IntersectClipRect(clip);
} }
layer = imageLayer; layer = imageLayer;
mLayerBuilder->StoreOptimizedLayerForFrame(data->mImage->GetUnderlyingFrame(),
data->mImage->GetPerFrameKey(),
imageLayer);
} else { } else {
nsRefPtr<ColorLayer> colorLayer = CreateOrRecycleColorLayer(data->mLayer); nsRefPtr<ColorLayer> colorLayer = CreateOrRecycleColorLayer(data->mLayer);
colorLayer->SetIsFixedPosition(data->mLayer->GetIsFixedPosition()); colorLayer->SetIsFixedPosition(data->mLayer->GetIsFixedPosition());
@ -2991,6 +3013,10 @@ FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, uint32_t aDisplayItemKey)
return nullptr; return nullptr;
} }
if (data->mOptLayer) {
return data->mOptLayer;
}
Layer* layer = data->mLayer; Layer* layer = data->mLayer;
if (!layer->HasUserData(&gColorLayerUserData) && if (!layer->HasUserData(&gColorLayerUserData) &&
!layer->HasUserData(&gImageLayerUserData) && !layer->HasUserData(&gImageLayerUserData) &&

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

@ -13,6 +13,7 @@
#include "nsIFrame.h" #include "nsIFrame.h"
#include "nsDisplayListInvalidation.h" #include "nsDisplayListInvalidation.h"
#include "LayerTreeInvalidation.h" #include "LayerTreeInvalidation.h"
#include "ImageLayers.h"
class nsDisplayListBuilder; class nsDisplayListBuilder;
class nsDisplayList; class nsDisplayList;
@ -100,6 +101,7 @@ public:
typedef layers::ContainerLayer ContainerLayer; typedef layers::ContainerLayer ContainerLayer;
typedef layers::Layer Layer; typedef layers::Layer Layer;
typedef layers::ThebesLayer ThebesLayer; typedef layers::ThebesLayer ThebesLayer;
typedef layers::ImageLayer ImageLayer;
typedef layers::LayerManager LayerManager; typedef layers::LayerManager LayerManager;
FrameLayerBuilder() : FrameLayerBuilder() :
@ -410,6 +412,14 @@ public:
*/ */
static gfxSize GetThebesLayerScaleForFrame(nsIFrame* aFrame); static gfxSize GetThebesLayerScaleForFrame(nsIFrame* aFrame);
/**
* Stores a Layer as the dedicated layer in the DisplayItemData for a given frame/key pair.
*
* Used when we optimize a ThebesLayer into an ImageLayer and want to retroactively update the
* DisplayItemData so we can retrieve the layer from within layout.
*/
void StoreOptimizedLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey, Layer* aImage);
/** /**
* Clip represents the intersection of an optional rectangle with a * Clip represents the intersection of an optional rectangle with a
* list of rounded rectangles. * list of rounded rectangles.
@ -534,6 +544,7 @@ protected:
bool FrameListMatches(nsDisplayItem* aOther); bool FrameListMatches(nsDisplayItem* aOther);
nsRefPtr<Layer> mLayer; nsRefPtr<Layer> mLayer;
nsRefPtr<Layer> mOptLayer;
nsRefPtr<LayerManager> mInactiveManager; nsRefPtr<LayerManager> mInactiveManager;
nsAutoTArray<nsIFrame*, 2> mFrameList; nsAutoTArray<nsIFrame*, 2> mFrameList;
nsAutoPtr<nsDisplayItemGeometry> mGeometry; nsAutoPtr<nsDisplayItemGeometry> mGeometry;

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

@ -679,11 +679,7 @@ nsImageFrame::FrameChanged(imgIRequest *aRequest,
return NS_OK; return NS_OK;
} }
if (aDirtyRect->IsEqualInterior(nsIntRect::GetMaxSizedIntRect())) { InvalidateLayer(nsDisplayItem::TYPE_IMAGE);
InvalidateFrame();
} else {
InvalidateFrameWithRect(SourceRectToDest(*aDirtyRect));
}
return NS_OK; return NS_OK;
} }

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

@ -638,9 +638,8 @@ NS_IMETHODIMP nsImageBoxFrame::FrameChanged(imgIRequest *aRequest,
if ((0 == mRect.width) || (0 == mRect.height)) { if ((0 == mRect.width) || (0 == mRect.height)) {
return NS_OK; return NS_OK;
} }
nsBoxLayoutState state(PresContext()); InvalidateLayer(nsDisplayItem::TYPE_XUL_IMAGE);
this->Redraw(state);
return NS_OK; return NS_OK;
} }