mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 781053 - Part 2 - Trigger empty transactions when an animated image in an ImageLayer changes frame. r=roc
This commit is contained in:
parent
f4e72f1dd0
commit
5b541f16bf
@ -171,7 +171,8 @@ RasterImage::RasterImage(imgStatusTracker* aStatusTracker) :
|
||||
mHasBeenDecoded(false),
|
||||
mInDecoder(false),
|
||||
mAnimationFinished(false),
|
||||
mFinishing(false)
|
||||
mFinishing(false),
|
||||
mInUpdateImageContainer(false)
|
||||
{
|
||||
// Set up the discard tracker node.
|
||||
mDiscardTrackerNode.img = this;
|
||||
@ -292,7 +293,6 @@ RasterImage::AdvanceFrame(TimeStamp aTime, nsIntRect* aDirtyRect)
|
||||
uint32_t currentFrameIndex = mAnim->currentAnimationFrameIndex;
|
||||
uint32_t nextFrameIndex = mAnim->currentAnimationFrameIndex + 1;
|
||||
uint32_t timeout = 0;
|
||||
mImageContainer = nullptr;
|
||||
|
||||
// Figure out if we have the next full frame. This is more complicated than
|
||||
// just checking for mFrames.Length() because decoders append their frames
|
||||
@ -439,6 +439,7 @@ RasterImage::RequestRefresh(const mozilla::TimeStamp& aTime)
|
||||
mFramesNotified++;
|
||||
#endif
|
||||
|
||||
UpdateImageContainer();
|
||||
observer->FrameChanged(nullptr, this, &dirtyRect);
|
||||
}
|
||||
}
|
||||
@ -862,6 +863,28 @@ RasterImage::GetFrame(uint32_t aWhichFrame,
|
||||
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
|
||||
RasterImage::GetImageContainer(ImageContainer **_retval)
|
||||
@ -872,24 +895,12 @@ RasterImage::GetImageContainer(ImageContainer **_retval)
|
||||
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();
|
||||
|
||||
// Now create a CairoImage to display the surface.
|
||||
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);
|
||||
nsRefPtr<layers::Image> image = GetCurrentImage();
|
||||
if (!image) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mImageContainer->SetCurrentImageInTransaction(image);
|
||||
|
||||
*_retval = mImageContainer;
|
||||
@ -897,6 +908,23 @@ RasterImage::GetImageContainer(ImageContainer **_retval)
|
||||
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
|
||||
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!");
|
||||
|
||||
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
|
||||
@ -1380,7 +1411,7 @@ RasterImage::ResetAnimation()
|
||||
|
||||
mAnim->lastCompositedFrameIndex = -1;
|
||||
mAnim->currentAnimationFrameIndex = 0;
|
||||
mImageContainer = nullptr;
|
||||
UpdateImageContainer();
|
||||
|
||||
// Note - We probably want to kick off a redecode somewhere around here when
|
||||
// we fix bug 500402.
|
||||
|
@ -127,6 +127,7 @@ namespace mozilla {
|
||||
namespace layers {
|
||||
class LayerManager;
|
||||
class ImageContainer;
|
||||
class Image;
|
||||
}
|
||||
namespace image {
|
||||
|
||||
@ -574,6 +575,12 @@ private:
|
||||
|
||||
bool ApplyDecodeFlags(uint32_t aNewFlags);
|
||||
|
||||
already_AddRefed<layers::Image> GetCurrentImage();
|
||||
void UpdateImageContainer();
|
||||
|
||||
void SetInUpdateImageContainer(bool aInUpdate) { mInUpdateImageContainer = aInUpdate; }
|
||||
bool IsInUpdateImageContainer() { return mInUpdateImageContainer; }
|
||||
|
||||
private: // data
|
||||
|
||||
nsIntSize mSize;
|
||||
@ -654,6 +661,8 @@ private: // data
|
||||
// Whether we're calling Decoder::Finish() from ShutdownDecoder.
|
||||
bool mFinishing:1;
|
||||
|
||||
bool mInUpdateImageContainer:1;
|
||||
|
||||
// Decoding
|
||||
nsresult WantDecodedFrames();
|
||||
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
|
||||
FrameLayerBuilder::DidEndTransaction()
|
||||
{
|
||||
@ -1610,6 +1629,9 @@ ContainerState::PopThebesLayerData()
|
||||
imageLayer->IntersectClipRect(clip);
|
||||
}
|
||||
layer = imageLayer;
|
||||
mLayerBuilder->StoreOptimizedLayerForFrame(data->mImage->GetUnderlyingFrame(),
|
||||
data->mImage->GetPerFrameKey(),
|
||||
imageLayer);
|
||||
} else {
|
||||
nsRefPtr<ColorLayer> colorLayer = CreateOrRecycleColorLayer(data->mLayer);
|
||||
colorLayer->SetIsFixedPosition(data->mLayer->GetIsFixedPosition());
|
||||
@ -2991,6 +3013,10 @@ FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, uint32_t aDisplayItemKey)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (data->mOptLayer) {
|
||||
return data->mOptLayer;
|
||||
}
|
||||
|
||||
Layer* layer = data->mLayer;
|
||||
if (!layer->HasUserData(&gColorLayerUserData) &&
|
||||
!layer->HasUserData(&gImageLayerUserData) &&
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "nsIFrame.h"
|
||||
#include "nsDisplayListInvalidation.h"
|
||||
#include "LayerTreeInvalidation.h"
|
||||
#include "ImageLayers.h"
|
||||
|
||||
class nsDisplayListBuilder;
|
||||
class nsDisplayList;
|
||||
@ -100,6 +101,7 @@ public:
|
||||
typedef layers::ContainerLayer ContainerLayer;
|
||||
typedef layers::Layer Layer;
|
||||
typedef layers::ThebesLayer ThebesLayer;
|
||||
typedef layers::ImageLayer ImageLayer;
|
||||
typedef layers::LayerManager LayerManager;
|
||||
|
||||
FrameLayerBuilder() :
|
||||
@ -410,6 +412,14 @@ public:
|
||||
*/
|
||||
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
|
||||
* list of rounded rectangles.
|
||||
@ -534,6 +544,7 @@ protected:
|
||||
bool FrameListMatches(nsDisplayItem* aOther);
|
||||
|
||||
nsRefPtr<Layer> mLayer;
|
||||
nsRefPtr<Layer> mOptLayer;
|
||||
nsRefPtr<LayerManager> mInactiveManager;
|
||||
nsAutoTArray<nsIFrame*, 2> mFrameList;
|
||||
nsAutoPtr<nsDisplayItemGeometry> mGeometry;
|
||||
|
@ -679,11 +679,7 @@ nsImageFrame::FrameChanged(imgIRequest *aRequest,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aDirtyRect->IsEqualInterior(nsIntRect::GetMaxSizedIntRect())) {
|
||||
InvalidateFrame();
|
||||
} else {
|
||||
InvalidateFrameWithRect(SourceRectToDest(*aDirtyRect));
|
||||
}
|
||||
InvalidateLayer(nsDisplayItem::TYPE_IMAGE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -638,9 +638,8 @@ NS_IMETHODIMP nsImageBoxFrame::FrameChanged(imgIRequest *aRequest,
|
||||
if ((0 == mRect.width) || (0 == mRect.height)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsBoxLayoutState state(PresContext());
|
||||
this->Redraw(state);
|
||||
|
||||
InvalidateLayer(nsDisplayItem::TYPE_XUL_IMAGE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user