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 mozilla_imagelib_FrameBlender_h_ michael@0: #define mozilla_imagelib_FrameBlender_h_ michael@0: michael@0: #include "mozilla/MemoryReporting.h" michael@0: #include "gfxTypes.h" michael@0: #include "FrameSequence.h" michael@0: #include "nsCOMPtr.h" michael@0: michael@0: class imgFrame; michael@0: michael@0: namespace mozilla { michael@0: namespace image { michael@0: michael@0: /** michael@0: * FrameBlender stores and gives access to imgFrames. It also knows how to michael@0: * blend frames from previous to next, looping if necessary. michael@0: * michael@0: * All logic about when and whether to blend are external to FrameBlender. michael@0: */ michael@0: class FrameBlender michael@0: { michael@0: public: michael@0: michael@0: /** michael@0: * Create a new FrameBlender with a given frame sequence. michael@0: * michael@0: * If aSequenceToUse is not specified, it will be allocated automatically. michael@0: */ michael@0: FrameBlender(FrameSequence* aSequenceToUse = nullptr); michael@0: ~FrameBlender(); michael@0: michael@0: bool DoBlend(nsIntRect* aDirtyRect, uint32_t aPrevFrameIndex, michael@0: uint32_t aNextFrameIndex); michael@0: michael@0: already_AddRefed GetFrameSequence(); michael@0: michael@0: /** michael@0: * Get the @aIndex-th frame, including (if applicable) any results of michael@0: * blending. michael@0: */ michael@0: imgFrame* GetFrame(uint32_t aIndex) const; michael@0: michael@0: /** michael@0: * Get the @aIndex-th frame in the frame index, ignoring results of blending. michael@0: */ michael@0: imgFrame* RawGetFrame(uint32_t aIndex) const; michael@0: michael@0: void InsertFrame(uint32_t framenum, imgFrame* aFrame); michael@0: void RemoveFrame(uint32_t framenum); michael@0: imgFrame* SwapFrame(uint32_t framenum, imgFrame* aFrame); michael@0: void ClearFrames(); michael@0: michael@0: /* The total number of frames in this image. */ michael@0: uint32_t GetNumFrames() const; michael@0: michael@0: /* michael@0: * Returns the frame's adjusted timeout. If the animation loops and the timeout michael@0: * falls in between a certain range then the timeout is adjusted so that michael@0: * it's never 0. If the animation does not loop then no adjustments are made. michael@0: */ michael@0: int32_t GetTimeoutForFrame(uint32_t framenum) const; michael@0: michael@0: /* michael@0: * Set number of times to loop the image. michael@0: * @note -1 means loop forever. michael@0: */ michael@0: void SetLoopCount(int32_t aLoopCount); michael@0: int32_t GetLoopCount() const; michael@0: michael@0: void Discard(); michael@0: michael@0: void SetSize(nsIntSize aSize) { mSize = aSize; } michael@0: michael@0: size_t SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation, michael@0: mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: void ResetAnimation(); michael@0: michael@0: // "Blend" method indicates how the current image is combined with the michael@0: // previous image. michael@0: enum FrameBlendMethod { michael@0: // All color components of the frame, including alpha, overwrite the current michael@0: // contents of the frame's output buffer region michael@0: kBlendSource = 0, michael@0: michael@0: // The frame should be composited onto the output buffer based on its alpha, michael@0: // using a simple OVER operation michael@0: kBlendOver michael@0: }; michael@0: michael@0: enum FrameDisposalMethod { michael@0: kDisposeClearAll = -1, // Clear the whole image, revealing michael@0: // what was there before the gif displayed michael@0: kDisposeNotSpecified, // Leave frame, let new frame draw on top michael@0: kDisposeKeep, // Leave frame, let new frame draw on top michael@0: kDisposeClear, // Clear the frame's area, revealing bg michael@0: kDisposeRestorePrevious // Restore the previous (composited) frame michael@0: }; michael@0: michael@0: // A hint as to whether an individual frame is entirely opaque, or requires michael@0: // alpha blending. michael@0: enum FrameAlpha { michael@0: kFrameHasAlpha, michael@0: kFrameOpaque michael@0: }; michael@0: michael@0: private: michael@0: michael@0: struct Anim michael@0: { michael@0: //! Track the last composited frame for Optimizations (See DoComposite code) michael@0: int32_t lastCompositedFrameIndex; michael@0: michael@0: /** For managing blending of frames michael@0: * michael@0: * Some animations will use the compositingFrame to composite images michael@0: * and just hand this back to the caller when it is time to draw the frame. michael@0: * NOTE: When clearing compositingFrame, remember to set michael@0: * lastCompositedFrameIndex to -1. Code assume that if michael@0: * lastCompositedFrameIndex >= 0 then compositingFrame exists. michael@0: */ michael@0: FrameDataPair compositingFrame; michael@0: michael@0: /** the previous composited frame, for DISPOSE_RESTORE_PREVIOUS michael@0: * michael@0: * The Previous Frame (all frames composited up to the current) needs to be michael@0: * stored in cases where the image specifies it wants the last frame back michael@0: * when it's done with the current frame. michael@0: */ michael@0: FrameDataPair compositingPrevFrame; michael@0: michael@0: Anim() : michael@0: lastCompositedFrameIndex(-1) michael@0: {} michael@0: }; michael@0: michael@0: void EnsureAnimExists(); michael@0: michael@0: /** Clears an area of with transparent black. michael@0: * michael@0: * @param aFrameData Target Frame data michael@0: * @param aFrameRect The rectangle of the data pointed ot by aFrameData michael@0: * michael@0: * @note Does also clears the transparancy mask michael@0: */ michael@0: static void ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect); michael@0: michael@0: //! @overload michael@0: static void ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect, const nsIntRect &aRectToClear); michael@0: michael@0: //! Copy one frames's image and mask into another michael@0: static bool CopyFrameImage(const uint8_t *aDataSrc, const nsIntRect& aRectSrc, michael@0: uint8_t *aDataDest, const nsIntRect& aRectDest); michael@0: michael@0: /** michael@0: * Draws one frames's image to into another, at the position specified by michael@0: * aSrcRect. michael@0: * michael@0: * @aSrcData the raw data of the current frame being drawn michael@0: * @aSrcRect the size of the source frame, and the position of that frame in michael@0: * the composition frame michael@0: * @aSrcPaletteLength the length (in bytes) of the palette at the beginning michael@0: * of the source data (0 if image is not paletted) michael@0: * @aSrcHasAlpha whether the source data represents an image with alpha michael@0: * @aDstPixels the raw data of the composition frame where the current frame michael@0: * is drawn into (32-bit ARGB) michael@0: * @aDstRect the size of the composition frame michael@0: * @aBlendMethod the blend method for how to blend src on the composition frame. michael@0: */ michael@0: static nsresult DrawFrameTo(const uint8_t *aSrcData, const nsIntRect& aSrcRect, michael@0: uint32_t aSrcPaletteLength, bool aSrcHasAlpha, michael@0: uint8_t *aDstPixels, const nsIntRect& aDstRect, michael@0: FrameBlendMethod aBlendMethod); michael@0: michael@0: private: // data michael@0: //! All the frames of the image michael@0: nsRefPtr mFrames; michael@0: nsIntSize mSize; michael@0: Anim* mAnim; michael@0: int32_t mLoopCount; michael@0: }; michael@0: michael@0: } // namespace image michael@0: } // namespace mozilla michael@0: michael@0: #endif /* mozilla_imagelib_FrameBlender_h_ */