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 {
33 typedef gfx::Color Color
;
34 typedef gfx::DataSourceSurface DataSourceSurface
;
35 typedef gfx::DrawTarget DrawTarget
;
36 typedef gfx::SamplingFilter SamplingFilter
;
37 typedef gfx::IntPoint IntPoint
;
38 typedef gfx::IntRect IntRect
;
39 typedef gfx::IntSize IntSize
;
40 typedef gfx::SourceSurface SourceSurface
;
41 typedef gfx::SurfaceFormat SurfaceFormat
;
44 MOZ_DECLARE_REFCOUNTED_TYPENAME(imgFrame
)
45 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(imgFrame
)
50 * Initialize this imgFrame with an empty surface and prepare it for being
51 * written to by a decoder.
53 * This is appropriate for use with decoded images, but it should not be used
54 * when drawing content into an imgFrame, as it may use a different graphics
55 * backend than normal content drawing.
57 nsresult
InitForDecoder(const nsIntSize
& aImageSize
,
58 const nsIntRect
& aRect
,
59 SurfaceFormat aFormat
,
60 uint8_t aPaletteDepth
= 0,
61 bool aNonPremult
= false,
62 const Maybe
<AnimationParams
>& aAnimParams
= Nothing());
64 nsresult
InitForAnimator(const nsIntSize
& aSize
,
65 SurfaceFormat aFormat
)
67 nsIntRect
frameRect(0, 0, aSize
.width
, aSize
.height
);
68 AnimationParams animParams
{ frameRect
, FrameTimeout::Forever(),
69 /* aFrameNum */ 1, BlendMethod::OVER
,
70 DisposalMethod::NOT_SPECIFIED
};
71 return InitForDecoder(aSize
, frameRect
,
72 aFormat
, 0, false, Some(animParams
));
77 * Initialize this imgFrame with a new surface and draw the provided
78 * gfxDrawable into it.
80 * This is appropriate to use when drawing content into an imgFrame, as it
81 * uses the same graphics backend as normal content drawing. The downside is
82 * that the underlying surface may not be stored in a volatile buffer on all
83 * platforms, and raw access to the surface (using RawAccessRef()) may be much
84 * more expensive than in the InitForDecoder() case.
86 * aBackend specifies the DrawTarget backend type this imgFrame is supposed
89 nsresult
InitWithDrawable(gfxDrawable
* aDrawable
,
90 const nsIntSize
& aSize
,
91 const SurfaceFormat aFormat
,
92 SamplingFilter aSamplingFilter
,
94 gfx::BackendType aBackend
);
96 DrawableFrameRef
DrawableRef();
99 * Create a RawAccessFrameRef for the frame.
101 * @param aOnlyFinished If true, only return a valid RawAccessFrameRef if
102 * imgFrame::Finish has been called.
104 RawAccessFrameRef
RawAccessRef(bool aOnlyFinished
= false);
107 * Make this imgFrame permanently available for raw access.
109 * This is irrevocable, and should be avoided whenever possible, since it
110 * prevents this imgFrame from being optimized and makes it impossible for its
111 * volatile buffer to be freed.
113 * It is an error to call this without already holding a RawAccessFrameRef to
116 void SetRawAccessOnly();
118 bool Draw(gfxContext
* aContext
, const ImageRegion
& aRegion
,
119 SamplingFilter aSamplingFilter
, uint32_t aImageFlags
,
122 nsresult
ImageUpdated(const nsIntRect
& aUpdateRect
);
125 * Mark this imgFrame as completely decoded, and set final options.
127 * You must always call either Finish() or Abort() before releasing the last
128 * RawAccessFrameRef pointing to an imgFrame.
130 * @param aFrameOpacity Whether this imgFrame is opaque.
131 * @param aFinalize Finalize the underlying surface (e.g. so that it
132 * may be marked as read only if possible).
134 void Finish(Opacity aFrameOpacity
= Opacity::SOME_TRANSPARENCY
,
135 bool aFinalize
= true);
138 * Mark this imgFrame as aborted. This informs the imgFrame that if it isn't
139 * completely decoded now, it never will be.
141 * You must always call either Finish() or Abort() before releasing the last
142 * RawAccessFrameRef pointing to an imgFrame.
147 * Returns true if this imgFrame has been aborted.
149 bool IsAborted() const;
152 * Returns true if this imgFrame is completely decoded.
154 bool IsFinished() const;
157 * Blocks until this imgFrame is either completely decoded, or is marked as
160 * Note that calling this on the main thread _blocks the main thread_. Be very
161 * careful in your use of this method to avoid excessive main thread jank or
164 void WaitUntilFinished() const;
167 * Returns the number of bytes per pixel this imgFrame requires. This is a
168 * worst-case value that does not take into account the effects of format
169 * changes caused by Optimize(), since an imgFrame is not optimized throughout
172 uint32_t GetBytesPerPixel() const { return GetIsPaletted() ? 1 : 4; }
174 const IntSize
& GetImageSize() const { return mImageSize
; }
175 const IntRect
& GetRect() const { return mFrameRect
; }
176 IntSize
GetSize() const { return mFrameRect
.Size(); }
177 const IntRect
& GetBlendRect() const { return mBlendRect
; }
178 IntRect
GetBoundedBlendRect() const { return mBlendRect
.Intersect(mFrameRect
); }
179 FrameTimeout
GetTimeout() const { return mTimeout
; }
180 BlendMethod
GetBlendMethod() const { return mBlendMethod
; }
181 DisposalMethod
GetDisposalMethod() const { return mDisposalMethod
; }
182 bool FormatHasAlpha() const { return mFormat
== SurfaceFormat::B8G8R8A8
; }
183 void GetImageData(uint8_t** aData
, uint32_t* length
) const;
184 uint8_t* GetImageData() const;
186 bool GetIsPaletted() const;
187 void GetPaletteData(uint32_t** aPalette
, uint32_t* length
) const;
188 uint32_t* GetPaletteData() const;
189 uint8_t GetPaletteDepth() const { return mPaletteDepth
; }
191 bool GetCompositingFailed() const;
192 void SetCompositingFailed(bool val
);
194 void SetOptimizable();
196 void FinalizeSurface();
197 already_AddRefed
<SourceSurface
> GetSourceSurface();
199 void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf
, size_t& aHeapSizeOut
,
200 size_t& aNonHeapSizeOut
,
201 size_t& aExtHandlesOut
) const;
208 * Used when the caller desires raw access to the underlying frame buffer.
209 * If the locking succeeds, the data pointer to the start of the buffer is
210 * returned, else it returns nullptr.
212 * @param aOnlyFinished If true, only attempt to lock if imgFrame::Finish has
215 uint8_t* LockImageData(bool aOnlyFinished
);
216 nsresult
UnlockImageData();
217 nsresult
Optimize(gfx::DrawTarget
* aTarget
);
219 void AssertImageDataLocked() const;
221 bool AreAllPixelsWritten() const;
222 nsresult
ImageUpdatedInternal(const nsIntRect
& aUpdateRect
);
223 void GetImageDataInternal(uint8_t** aData
, uint32_t* length
) const;
224 uint32_t GetImageBytesPerRow() const;
225 uint32_t GetImageDataLength() const;
226 void FinalizeSurfaceInternal();
227 already_AddRefed
<SourceSurface
> GetSourceSurfaceInternal();
229 uint32_t PaletteDataLength() const
231 return mPaletteDepth
? (size_t(1) << mPaletteDepth
) * sizeof(uint32_t)
235 struct SurfaceWithFormat
{
236 RefPtr
<gfxDrawable
> mDrawable
;
237 SurfaceFormat mFormat
;
239 : mFormat(SurfaceFormat::UNKNOWN
)
242 SurfaceWithFormat(gfxDrawable
* aDrawable
, SurfaceFormat aFormat
)
243 : mDrawable(aDrawable
), mFormat(aFormat
)
245 bool IsValid() { return !!mDrawable
; }
248 SurfaceWithFormat
SurfaceForDrawing(bool aDoPartialDecode
,
250 ImageRegion
& aRegion
,
251 SourceSurface
* aSurface
);
254 friend class DrawableFrameRef
;
255 friend class RawAccessFrameRef
;
256 friend class UnlockImageDataRunnable
;
258 //////////////////////////////////////////////////////////////////////////////
259 // Thread-safe mutable data, protected by mMonitor.
260 //////////////////////////////////////////////////////////////////////////////
262 mutable Monitor mMonitor
;
265 * Surface which contains either a weak or a strong reference to its
266 * underlying data buffer. If it is a weak reference, and there are no strong
267 * references, the buffer may be released due to events such as low memory.
269 RefPtr
<DataSourceSurface
> mRawSurface
;
272 * Refers to the same data as mRawSurface, but when set, it guarantees that
273 * we hold a strong reference to the underlying data buffer.
275 RefPtr
<DataSourceSurface
> mLockedSurface
;
278 * Optimized copy of mRawSurface for the DrawTarget that will render it. This
279 * is unused if the DrawTarget is able to render DataSourceSurface buffers
282 RefPtr
<SourceSurface
> mOptSurface
;
286 //! Number of RawAccessFrameRefs currently alive for this imgFrame.
294 //////////////////////////////////////////////////////////////////////////////
295 // Effectively const data, only mutated in the Init methods.
296 //////////////////////////////////////////////////////////////////////////////
302 //! The timeout for this frame.
303 FrameTimeout mTimeout
;
305 DisposalMethod mDisposalMethod
;
306 BlendMethod mBlendMethod
;
307 SurfaceFormat mFormat
;
309 // The palette and image data for images that are paletted, since Cairo
310 // doesn't support these images.
311 // The paletted data comes first, then the image data itself.
312 // Total length is PaletteDataLength() + GetImageDataLength().
313 uint8_t* mPalettedImageData
;
314 uint8_t mPaletteDepth
;
319 //////////////////////////////////////////////////////////////////////////////
320 // Main-thread-only mutable data.
321 //////////////////////////////////////////////////////////////////////////////
323 bool mCompositingFailed
;
327 * A reference to an imgFrame that holds the imgFrame's surface in memory,
328 * allowing drawing. If you have a DrawableFrameRef |ref| and |if (ref)| returns
329 * true, then calls to Draw() and GetSourceSurface() are guaranteed to succeed.
331 class DrawableFrameRef final
333 typedef gfx::DataSourceSurface DataSourceSurface
;
336 DrawableFrameRef() { }
338 explicit DrawableFrameRef(imgFrame
* aFrame
)
342 MonitorAutoLock
lock(aFrame
->mMonitor
);
343 MOZ_ASSERT(!aFrame
->GetIsPaletted(), "Paletted must use RawAccessFrameRef");
345 if (aFrame
->mRawSurface
) {
346 mRef
.emplace(aFrame
->mRawSurface
, DataSourceSurface::READ
);
347 if (!mRef
->IsMapped()) {
352 MOZ_ASSERT(aFrame
->mOptSurface
);
356 DrawableFrameRef(DrawableFrameRef
&& aOther
)
357 : mFrame(aOther
.mFrame
.forget())
358 , mRef(std::move(aOther
.mRef
))
361 DrawableFrameRef
& operator=(DrawableFrameRef
&& aOther
)
363 MOZ_ASSERT(this != &aOther
, "Self-moves are prohibited");
364 mFrame
= aOther
.mFrame
.forget();
365 mRef
= std::move(aOther
.mRef
);
369 explicit operator bool() const { return bool(mFrame
); }
371 imgFrame
* operator->()
377 const imgFrame
* operator->() const
383 imgFrame
* get() { return mFrame
; }
384 const imgFrame
* get() const { return mFrame
; }
393 DrawableFrameRef(const DrawableFrameRef
& aOther
) = delete;
394 DrawableFrameRef
& operator=(const DrawableFrameRef
& aOther
) = delete;
396 RefPtr
<imgFrame
> mFrame
;
397 Maybe
<DataSourceSurface::ScopedMap
> mRef
;
401 * A reference to an imgFrame that holds the imgFrame's surface in memory in a
402 * format appropriate for access as raw data. If you have a RawAccessFrameRef
403 * |ref| and |if (ref)| is true, then calls to GetImageData() and
404 * GetPaletteData() are guaranteed to succeed. This guarantee is stronger than
405 * DrawableFrameRef, so everything that a valid DrawableFrameRef guarantees is
406 * also guaranteed by a valid RawAccessFrameRef.
408 * This may be considerably more expensive than is necessary just for drawing,
409 * so only use this when you need to read or write the raw underlying image data
410 * that the imgFrame holds.
412 * Once all an imgFrame's RawAccessFrameRefs go out of scope, new
413 * RawAccessFrameRefs cannot be created.
415 class RawAccessFrameRef final
418 RawAccessFrameRef() : mData(nullptr) { }
420 explicit RawAccessFrameRef(imgFrame
* aFrame
,
425 MOZ_ASSERT(mFrame
, "Need a frame");
427 mData
= mFrame
->LockImageData(aOnlyFinished
);
433 RawAccessFrameRef(RawAccessFrameRef
&& aOther
)
434 : mFrame(aOther
.mFrame
.forget())
435 , mData(aOther
.mData
)
437 aOther
.mData
= nullptr;
443 mFrame
->UnlockImageData();
447 RawAccessFrameRef
& operator=(RawAccessFrameRef
&& aOther
)
449 MOZ_ASSERT(this != &aOther
, "Self-moves are prohibited");
452 mFrame
->UnlockImageData();
455 mFrame
= aOther
.mFrame
.forget();
456 mData
= aOther
.mData
;
457 aOther
.mData
= nullptr;
462 explicit operator bool() const { return bool(mFrame
); }
464 imgFrame
* operator->()
470 const imgFrame
* operator->() const
476 imgFrame
* get() { return mFrame
; }
477 const imgFrame
* get() const { return mFrame
; }
482 mFrame
->UnlockImageData();
488 uint8_t* Data() const { return mData
; }
489 uint32_t PaletteDataLength() const { return mFrame
->PaletteDataLength(); }
492 RawAccessFrameRef(const RawAccessFrameRef
& aOther
) = delete;
493 RawAccessFrameRef
& operator=(const RawAccessFrameRef
& aOther
) = delete;
495 RefPtr
<imgFrame
> mFrame
;
500 } // namespace mozilla
502 #endif // mozilla_image_imgFrame_h