1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_image_imgFrame_h
8 #define mozilla_image_imgFrame_h
10 #include "mozilla/Maybe.h"
11 #include "mozilla/MemoryReporting.h"
12 #include "mozilla/Monitor.h"
13 #include "mozilla/Move.h"
14 #include "AnimationParams.h"
15 #include "gfxDrawable.h"
16 #include "imgIContainer.h"
17 #include "MainThreadUtils.h"
23 class DrawableFrameRef
;
24 class RawAccessFrameRef
;
26 enum class Opacity
: uint8_t { FULLY_OPAQUE
, SOME_TRANSPARENCY
};
29 typedef gfx::Color Color
;
30 typedef gfx::DataSourceSurface DataSourceSurface
;
31 typedef gfx::DrawTarget DrawTarget
;
32 typedef gfx::SamplingFilter SamplingFilter
;
33 typedef gfx::IntPoint IntPoint
;
34 typedef gfx::IntRect IntRect
;
35 typedef gfx::IntSize IntSize
;
36 typedef gfx::SourceSurface SourceSurface
;
37 typedef gfx::SurfaceFormat SurfaceFormat
;
40 MOZ_DECLARE_REFCOUNTED_TYPENAME(imgFrame
)
41 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(imgFrame
)
46 * Initialize this imgFrame with an empty surface and prepare it for being
47 * written to by a decoder.
49 * This is appropriate for use with decoded images, but it should not be used
50 * when drawing content into an imgFrame, as it may use a different graphics
51 * backend than normal content drawing.
53 nsresult
InitForDecoder(const nsIntSize
& aImageSize
, SurfaceFormat aFormat
,
55 const Maybe
<AnimationParams
>& aAnimParams
,
59 * Reinitialize this imgFrame with the new parameters, but otherwise retain
60 * the underlying buffer.
62 * This is appropriate for use with animated images, where the decoder was
63 * given an IDecoderFrameRecycler object which may yield a recycled imgFrame
64 * that was discarded to save memory.
66 nsresult
InitForDecoderRecycle(const AnimationParams
& aAnimParams
);
69 * Initialize this imgFrame with a new surface and draw the provided
70 * gfxDrawable into it.
72 * This is appropriate to use when drawing content into an imgFrame, as it
73 * uses the same graphics backend as normal content drawing. The downside is
74 * that the underlying surface may not be stored in a volatile buffer on all
75 * platforms, and raw access to the surface (using RawAccessRef()) may be much
76 * more expensive than in the InitForDecoder() case.
78 * aBackend specifies the DrawTarget backend type this imgFrame is supposed
81 nsresult
InitWithDrawable(gfxDrawable
* aDrawable
, const nsIntSize
& aSize
,
82 const SurfaceFormat aFormat
,
83 SamplingFilter aSamplingFilter
,
84 uint32_t aImageFlags
, gfx::BackendType aBackend
,
87 DrawableFrameRef
DrawableRef();
90 * Create a RawAccessFrameRef for the frame.
92 * @param aOnlyFinished If true, only return a valid RawAccessFrameRef if
93 * imgFrame::Finish has been called.
95 RawAccessFrameRef
RawAccessRef(bool aOnlyFinished
= false);
98 * Make this imgFrame permanently available for raw access.
100 * This is irrevocable, and should be avoided whenever possible, since it
101 * prevents this imgFrame from being optimized and makes it impossible for its
102 * volatile buffer to be freed.
104 * It is an error to call this without already holding a RawAccessFrameRef to
107 void SetRawAccessOnly();
109 bool Draw(gfxContext
* aContext
, const ImageRegion
& aRegion
,
110 SamplingFilter aSamplingFilter
, uint32_t aImageFlags
,
113 nsresult
ImageUpdated(const nsIntRect
& aUpdateRect
);
116 * Mark this imgFrame as completely decoded, and set final options.
118 * You must always call either Finish() or Abort() before releasing the last
119 * RawAccessFrameRef pointing to an imgFrame.
121 * @param aFrameOpacity Whether this imgFrame is opaque.
122 * @param aFinalize Finalize the underlying surface (e.g. so that it
123 * may be marked as read only if possible).
125 void Finish(Opacity aFrameOpacity
= Opacity::SOME_TRANSPARENCY
,
126 bool aFinalize
= true);
129 * Mark this imgFrame as aborted. This informs the imgFrame that if it isn't
130 * completely decoded now, it never will be.
132 * You must always call either Finish() or Abort() before releasing the last
133 * RawAccessFrameRef pointing to an imgFrame.
138 * Returns true if this imgFrame has been aborted.
140 bool IsAborted() const;
143 * Returns true if this imgFrame is completely decoded.
145 bool IsFinished() const;
148 * Blocks until this imgFrame is either completely decoded, or is marked as
151 * Note that calling this on the main thread _blocks the main thread_. Be very
152 * careful in your use of this method to avoid excessive main thread jank or
155 void WaitUntilFinished() const;
158 * Returns the number of bytes per pixel this imgFrame requires. This is a
159 * worst-case value that does not take into account the effects of format
160 * changes caused by Optimize(), since an imgFrame is not optimized throughout
163 uint32_t GetBytesPerPixel() const { return 4; }
165 const IntSize
& GetSize() const { return mImageSize
; }
166 IntRect
GetRect() const { return IntRect(IntPoint(0, 0), mImageSize
); }
167 const IntRect
& GetBlendRect() const { return mBlendRect
; }
168 IntRect
GetBoundedBlendRect() const {
169 return mBlendRect
.Intersect(GetRect());
171 FrameTimeout
GetTimeout() const { return mTimeout
; }
172 BlendMethod
GetBlendMethod() const { return mBlendMethod
; }
173 DisposalMethod
GetDisposalMethod() const { return mDisposalMethod
; }
174 bool FormatHasAlpha() const { return mFormat
== SurfaceFormat::B8G8R8A8
; }
175 void GetImageData(uint8_t** aData
, uint32_t* length
) const;
176 uint8_t* GetImageData() const;
178 const IntRect
& GetDirtyRect() const { return mDirtyRect
; }
179 void SetDirtyRect(const IntRect
& aDirtyRect
) { mDirtyRect
= aDirtyRect
; }
181 void SetOptimizable();
183 void FinalizeSurface();
184 already_AddRefed
<SourceSurface
> GetSourceSurface();
186 struct AddSizeOfCbData
{
188 : heap(0), nonHeap(0), handles(0), index(0), externalId(0) {}
197 typedef std::function
<void(AddSizeOfCbData
& aMetadata
)> AddSizeOfCb
;
199 void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf
,
200 const AddSizeOfCb
& aCallback
) const;
206 * Used when the caller desires raw access to the underlying frame buffer.
207 * If the locking succeeds, the data pointer to the start of the buffer is
208 * returned, else it returns nullptr.
210 * @param aOnlyFinished If true, only attempt to lock if imgFrame::Finish has
213 uint8_t* LockImageData(bool aOnlyFinished
);
214 nsresult
UnlockImageData();
215 nsresult
Optimize(gfx::DrawTarget
* aTarget
);
217 void AssertImageDataLocked() const;
219 bool AreAllPixelsWritten() const;
220 nsresult
ImageUpdatedInternal(const nsIntRect
& aUpdateRect
);
221 void GetImageDataInternal(uint8_t** aData
, uint32_t* length
) const;
222 uint32_t GetImageBytesPerRow() const;
223 uint32_t GetImageDataLength() const;
224 void FinalizeSurfaceInternal();
227 * @param aTemporary If true, it will assume the caller does not require a
228 * wrapping RecycleSourceSurface to protect the underlying
229 * surface from recycling. The reference to the surface
230 * must be freed before releasing the main thread context.
232 already_AddRefed
<SourceSurface
> GetSourceSurfaceInternal(bool aTemporary
);
234 struct SurfaceWithFormat
{
235 RefPtr
<gfxDrawable
> mDrawable
;
236 SurfaceFormat mFormat
;
237 SurfaceWithFormat() : mFormat(SurfaceFormat::UNKNOWN
) {}
238 SurfaceWithFormat(gfxDrawable
* aDrawable
, SurfaceFormat aFormat
)
239 : mDrawable(aDrawable
), mFormat(aFormat
) {}
240 SurfaceWithFormat(SurfaceWithFormat
&& aOther
)
241 : mDrawable(std::move(aOther
.mDrawable
)), mFormat(aOther
.mFormat
) {}
242 SurfaceWithFormat
& operator=(SurfaceWithFormat
&& aOther
) {
243 mDrawable
= std::move(aOther
.mDrawable
);
244 mFormat
= aOther
.mFormat
;
247 SurfaceWithFormat
& operator=(const SurfaceWithFormat
& aOther
) = delete;
248 SurfaceWithFormat(const SurfaceWithFormat
& aOther
) = delete;
249 bool IsValid() { return !!mDrawable
; }
252 SurfaceWithFormat
SurfaceForDrawing(bool aDoPartialDecode
, bool aDoTile
,
253 ImageRegion
& aRegion
,
254 SourceSurface
* aSurface
);
257 friend class DrawableFrameRef
;
258 friend class RawAccessFrameRef
;
259 friend class RecyclingSourceSurface
;
260 friend class UnlockImageDataRunnable
;
262 //////////////////////////////////////////////////////////////////////////////
263 // Thread-safe mutable data, protected by mMonitor.
264 //////////////////////////////////////////////////////////////////////////////
266 mutable Monitor mMonitor
;
269 * Surface which contains either a weak or a strong reference to its
270 * underlying data buffer. If it is a weak reference, and there are no strong
271 * references, the buffer may be released due to events such as low memory.
273 RefPtr
<DataSourceSurface
> mRawSurface
;
274 RefPtr
<DataSourceSurface
> mBlankRawSurface
;
277 * Refers to the same data as mRawSurface, but when set, it guarantees that
278 * we hold a strong reference to the underlying data buffer.
280 RefPtr
<DataSourceSurface
> mLockedSurface
;
281 RefPtr
<DataSourceSurface
> mBlankLockedSurface
;
284 * Optimized copy of mRawSurface for the DrawTarget that will render it. This
285 * is unused if the DrawTarget is able to render DataSourceSurface buffers
288 RefPtr
<SourceSurface
> mOptSurface
;
292 //! Number of RawAccessFrameRefs currently alive for this imgFrame.
295 //! Number of RecyclingSourceSurface's currently alive for this imgFrame.
296 int16_t mRecycleLockCount
;
303 //////////////////////////////////////////////////////////////////////////////
304 // Effectively const data, only mutated in the Init methods.
305 //////////////////////////////////////////////////////////////////////////////
307 //! The size of the buffer we are decoding to.
310 //! The contents for the frame, as represented in the encoded image. This may
311 //! differ from mImageSize because it may be a partial frame. For the first
312 //! frame, this means we need to shift the data in place, and for animated
313 //! frames, it likely need to combine with a previous frame to get the full
317 //! This is the region that has changed between this frame and the previous
318 //! frame of an animation. For the first frame, this will be the same as
322 //! The timeout for this frame.
323 FrameTimeout mTimeout
;
325 DisposalMethod mDisposalMethod
;
326 BlendMethod mBlendMethod
;
327 SurfaceFormat mFormat
;
333 * A reference to an imgFrame that holds the imgFrame's surface in memory,
334 * allowing drawing. If you have a DrawableFrameRef |ref| and |if (ref)| returns
335 * true, then calls to Draw() and GetSourceSurface() are guaranteed to succeed.
337 class DrawableFrameRef final
{
338 typedef gfx::DataSourceSurface DataSourceSurface
;
341 DrawableFrameRef() {}
343 explicit DrawableFrameRef(imgFrame
* aFrame
) : mFrame(aFrame
) {
345 MonitorAutoLock
lock(aFrame
->mMonitor
);
347 if (aFrame
->mRawSurface
) {
348 mRef
.emplace(aFrame
->mRawSurface
, DataSourceSurface::READ
);
349 if (!mRef
->IsMapped()) {
354 MOZ_ASSERT(aFrame
->mOptSurface
);
358 DrawableFrameRef(DrawableFrameRef
&& aOther
)
359 : mFrame(aOther
.mFrame
.forget()), mRef(std::move(aOther
.mRef
)) {}
361 DrawableFrameRef
& operator=(DrawableFrameRef
&& aOther
) {
362 MOZ_ASSERT(this != &aOther
, "Self-moves are prohibited");
363 mFrame
= aOther
.mFrame
.forget();
364 mRef
= std::move(aOther
.mRef
);
368 explicit operator bool() const { return bool(mFrame
); }
370 imgFrame
* operator->() {
375 const imgFrame
* operator->() const {
380 imgFrame
* get() { return mFrame
; }
381 const imgFrame
* get() const { return mFrame
; }
389 DrawableFrameRef(const DrawableFrameRef
& aOther
) = delete;
390 DrawableFrameRef
& operator=(const DrawableFrameRef
& aOther
) = delete;
392 RefPtr
<imgFrame
> mFrame
;
393 Maybe
<DataSourceSurface::ScopedMap
> mRef
;
397 * A reference to an imgFrame that holds the imgFrame's surface in memory in a
398 * format appropriate for access as raw data. If you have a RawAccessFrameRef
399 * |ref| and |if (ref)| is true, then calls to GetImageData() is guaranteed to
400 * succeed. This guarantee is stronger than DrawableFrameRef, so everything that
401 * a valid DrawableFrameRef guarantees is also guaranteed by a valid
404 * This may be considerably more expensive than is necessary just for drawing,
405 * so only use this when you need to read or write the raw underlying image data
406 * that the imgFrame holds.
408 * Once all an imgFrame's RawAccessFrameRefs go out of scope, new
409 * RawAccessFrameRefs cannot be created.
411 class RawAccessFrameRef final
{
413 RawAccessFrameRef() : mData(nullptr) {}
415 explicit RawAccessFrameRef(imgFrame
* aFrame
, bool aOnlyFinished
)
416 : mFrame(aFrame
), mData(nullptr) {
417 MOZ_ASSERT(mFrame
, "Need a frame");
419 mData
= mFrame
->LockImageData(aOnlyFinished
);
425 RawAccessFrameRef(RawAccessFrameRef
&& aOther
)
426 : mFrame(aOther
.mFrame
.forget()), mData(aOther
.mData
) {
427 aOther
.mData
= nullptr;
430 ~RawAccessFrameRef() {
432 mFrame
->UnlockImageData();
436 RawAccessFrameRef
& operator=(RawAccessFrameRef
&& aOther
) {
437 MOZ_ASSERT(this != &aOther
, "Self-moves are prohibited");
440 mFrame
->UnlockImageData();
443 mFrame
= aOther
.mFrame
.forget();
444 mData
= aOther
.mData
;
445 aOther
.mData
= nullptr;
450 explicit operator bool() const { return bool(mFrame
); }
452 imgFrame
* operator->() {
457 const imgFrame
* operator->() const {
462 imgFrame
* get() { return mFrame
; }
463 const imgFrame
* get() const { return mFrame
; }
467 mFrame
->UnlockImageData();
473 uint8_t* Data() const { return mData
; }
476 RawAccessFrameRef(const RawAccessFrameRef
& aOther
) = delete;
477 RawAccessFrameRef
& operator=(const RawAccessFrameRef
& aOther
) = delete;
479 RefPtr
<imgFrame
> mFrame
;
484 } // namespace mozilla
486 #endif // mozilla_image_imgFrame_h