michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef imgFrame_h michael@0: #define imgFrame_h michael@0: michael@0: #include "mozilla/MemoryReporting.h" michael@0: #include "mozilla/Mutex.h" michael@0: #include "mozilla/VolatileBuffer.h" michael@0: #include "nsRect.h" michael@0: #include "nsPoint.h" michael@0: #include "nsSize.h" michael@0: #include "gfxPattern.h" michael@0: #include "gfxDrawable.h" michael@0: #include "gfxImageSurface.h" michael@0: #if defined(XP_WIN) michael@0: #include "gfxWindowsSurface.h" michael@0: #elif defined(XP_MACOSX) michael@0: #include "gfxQuartzImageSurface.h" michael@0: #endif michael@0: #include "nsAutoPtr.h" michael@0: #include "imgIContainer.h" michael@0: #include "gfxColor.h" michael@0: michael@0: /* michael@0: * This creates a gfxImageSurface which will unlock the buffer on destruction michael@0: */ michael@0: michael@0: class LockedImageSurface michael@0: { michael@0: public: michael@0: static gfxImageSurface * michael@0: CreateSurface(mozilla::VolatileBuffer *vbuf, michael@0: const gfxIntSize& size, michael@0: gfxImageFormat format); michael@0: static mozilla::TemporaryRef michael@0: AllocateBuffer(const gfxIntSize& size, gfxImageFormat format); michael@0: }; michael@0: michael@0: class imgFrame michael@0: { michael@0: public: michael@0: imgFrame(); michael@0: ~imgFrame(); michael@0: michael@0: nsresult Init(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, gfxImageFormat aFormat, uint8_t aPaletteDepth = 0); michael@0: nsresult Optimize(); michael@0: michael@0: bool Draw(gfxContext *aContext, GraphicsFilter aFilter, michael@0: const gfxMatrix &aUserSpaceToImageSpace, const gfxRect& aFill, michael@0: const nsIntMargin &aPadding, const nsIntRect &aSubimage, michael@0: uint32_t aImageFlags = imgIContainer::FLAG_NONE); michael@0: michael@0: nsresult ImageUpdated(const nsIntRect &aUpdateRect); michael@0: bool GetIsDirty() const; michael@0: michael@0: nsIntRect GetRect() const; michael@0: gfxImageFormat GetFormat() const; michael@0: bool GetNeedsBackground() const; michael@0: uint32_t GetImageBytesPerRow() const; michael@0: uint32_t GetImageDataLength() const; michael@0: bool GetIsPaletted() const; michael@0: bool GetHasAlpha() const; michael@0: void GetImageData(uint8_t **aData, uint32_t *length) const; michael@0: uint8_t* GetImageData() const; michael@0: void GetPaletteData(uint32_t **aPalette, uint32_t *length) const; michael@0: uint32_t* GetPaletteData() const; michael@0: michael@0: int32_t GetRawTimeout() const; michael@0: void SetRawTimeout(int32_t aTimeout); michael@0: michael@0: int32_t GetFrameDisposalMethod() const; michael@0: void SetFrameDisposalMethod(int32_t aFrameDisposalMethod); michael@0: int32_t GetBlendMethod() const; michael@0: void SetBlendMethod(int32_t aBlendMethod); michael@0: bool ImageComplete() const; michael@0: michael@0: void SetHasNoAlpha(); michael@0: void SetAsNonPremult(bool aIsNonPremult); michael@0: michael@0: bool GetCompositingFailed() const; michael@0: void SetCompositingFailed(bool val); michael@0: michael@0: nsresult LockImageData(); michael@0: nsresult UnlockImageData(); michael@0: void ApplyDirtToSurfaces(); michael@0: michael@0: void SetDiscardable(); michael@0: michael@0: nsresult GetSurface(gfxASurface **aSurface) michael@0: { michael@0: *aSurface = ThebesSurface(); michael@0: NS_IF_ADDREF(*aSurface); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult GetPattern(gfxPattern **aPattern) michael@0: { michael@0: if (mSinglePixel) michael@0: *aPattern = new gfxPattern(mSinglePixelColor); michael@0: else michael@0: *aPattern = new gfxPattern(ThebesSurface()); michael@0: NS_ADDREF(*aPattern); michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool IsSinglePixel() michael@0: { michael@0: return mSinglePixel; michael@0: } michael@0: michael@0: gfxASurface* CachedThebesSurface() michael@0: { michael@0: if (mOptSurface) michael@0: return mOptSurface; michael@0: #if defined(XP_WIN) michael@0: if (mWinSurface) michael@0: return mWinSurface; michael@0: #elif defined(XP_MACOSX) michael@0: if (mQuartzSurface) michael@0: return mQuartzSurface; michael@0: #endif michael@0: if (mImageSurface) michael@0: return mImageSurface; michael@0: return nullptr; michael@0: } michael@0: michael@0: gfxASurface* ThebesSurface() michael@0: { michael@0: gfxASurface *sur = CachedThebesSurface(); michael@0: if (sur) michael@0: return sur; michael@0: if (mVBuf) { michael@0: mozilla::VolatileBufferPtr ref(mVBuf); michael@0: if (ref.WasBufferPurged()) michael@0: return nullptr; michael@0: michael@0: gfxImageSurface *imgSur = michael@0: LockedImageSurface::CreateSurface(mVBuf, mSize, mFormat); michael@0: #if defined(XP_MACOSX) michael@0: // Manually addref and release to make sure the cairo surface isn't lost michael@0: NS_ADDREF(imgSur); michael@0: gfxQuartzImageSurface *quartzSur = new gfxQuartzImageSurface(imgSur); michael@0: // quartzSur does not hold on to the gfxImageSurface michael@0: NS_RELEASE(imgSur); michael@0: return quartzSur; michael@0: #else michael@0: return imgSur; michael@0: #endif michael@0: } michael@0: // We can return null here if we're single pixel optimized michael@0: // or a paletted image. However, one has to check for paletted michael@0: // image data first before attempting to get a surface, so michael@0: // this is only valid for single pixel optimized images michael@0: MOZ_ASSERT(mSinglePixel, "No image surface and not a single pixel!"); michael@0: return nullptr; michael@0: } michael@0: michael@0: size_t SizeOfExcludingThisWithComputedFallbackIfHeap( michael@0: gfxMemoryLocation aLocation, michael@0: mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: uint8_t GetPaletteDepth() const { return mPaletteDepth; } michael@0: uint32_t PaletteDataLength() const { michael@0: if (!mPaletteDepth) michael@0: return 0; michael@0: michael@0: return ((1 << mPaletteDepth) * sizeof(uint32_t)); michael@0: } michael@0: michael@0: private: // methods michael@0: michael@0: struct SurfaceWithFormat { michael@0: nsRefPtr mDrawable; michael@0: gfxImageFormat mFormat; michael@0: SurfaceWithFormat() {} michael@0: SurfaceWithFormat(gfxDrawable* aDrawable, gfxImageFormat aFormat) michael@0: : mDrawable(aDrawable), mFormat(aFormat) {} michael@0: bool IsValid() { return !!mDrawable; } michael@0: }; michael@0: michael@0: SurfaceWithFormat SurfaceForDrawing(bool aDoPadding, michael@0: bool aDoPartialDecode, michael@0: bool aDoTile, michael@0: const nsIntMargin& aPadding, michael@0: gfxMatrix& aUserSpaceToImageSpace, michael@0: gfxRect& aFill, michael@0: gfxRect& aSubimage, michael@0: gfxRect& aSourceRect, michael@0: gfxRect& aImageRect, michael@0: gfxASurface* aSurface); michael@0: michael@0: private: // data michael@0: nsRefPtr mImageSurface; michael@0: nsRefPtr mOptSurface; michael@0: #if defined(XP_WIN) michael@0: nsRefPtr mWinSurface; michael@0: #elif defined(XP_MACOSX) michael@0: nsRefPtr mQuartzSurface; michael@0: #endif michael@0: michael@0: nsRefPtr mDrawSurface; michael@0: michael@0: nsIntSize mSize; michael@0: nsIntPoint mOffset; michael@0: michael@0: nsIntRect mDecoded; michael@0: michael@0: mutable mozilla::Mutex mDirtyMutex; michael@0: michael@0: // The palette and image data for images that are paletted, since Cairo michael@0: // doesn't support these images. michael@0: // The paletted data comes first, then the image data itself. michael@0: // Total length is PaletteDataLength() + GetImageDataLength(). michael@0: uint8_t* mPalettedImageData; michael@0: michael@0: // Note that the data stored in gfxRGBA is *non-alpha-premultiplied*. michael@0: gfxRGBA mSinglePixelColor; michael@0: michael@0: int32_t mTimeout; // -1 means display forever michael@0: int32_t mDisposalMethod; michael@0: michael@0: /** Indicates how many readers currently have locked this frame */ michael@0: int32_t mLockCount; michael@0: michael@0: mozilla::RefPtr mVBuf; michael@0: michael@0: gfxImageFormat mFormat; michael@0: uint8_t mPaletteDepth; michael@0: int8_t mBlendMethod; michael@0: bool mSinglePixel; michael@0: bool mFormatChanged; michael@0: bool mCompositingFailed; michael@0: bool mNonPremult; michael@0: bool mDiscardable; michael@0: michael@0: /** Have we called DiscardTracker::InformAllocation()? */ michael@0: bool mInformedDiscardTracker; michael@0: michael@0: bool mDirty; michael@0: }; michael@0: michael@0: namespace mozilla { michael@0: namespace image { michael@0: // An RAII class to ensure it's easy to balance locks and unlocks on michael@0: // imgFrames. michael@0: class AutoFrameLocker michael@0: { michael@0: public: michael@0: AutoFrameLocker(imgFrame* frame) michael@0: : mFrame(frame) michael@0: , mSucceeded(NS_SUCCEEDED(frame->LockImageData())) michael@0: {} michael@0: michael@0: ~AutoFrameLocker() michael@0: { michael@0: if (mSucceeded) { michael@0: mFrame->UnlockImageData(); michael@0: } michael@0: } michael@0: michael@0: // Whether the lock request succeeded. michael@0: bool Succeeded() { return mSucceeded; } michael@0: michael@0: private: michael@0: imgFrame* mFrame; michael@0: bool mSucceeded; michael@0: }; michael@0: } michael@0: } michael@0: michael@0: #endif /* imgFrame_h */