зеркало из https://github.com/mozilla/gecko-dev.git
Bug 781053 - Part 2 - Trigger empty transactions when an animated image in an ImageLayer changes frame. r=roc
This commit is contained in:
Родитель
af81361caa
Коммит
53908eb696
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче