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
13 #include "AnimationParams.h"
14 #include "MainThreadUtils.h"
15 #include "gfxDrawable.h"
16 #include "mozilla/layers/SourceSurfaceSharedData.h"
17 #include "mozilla/Maybe.h"
18 #include "mozilla/MemoryReporting.h"
19 #include "mozilla/Monitor.h"
26 class DrawableFrameRef
;
27 class RawAccessFrameRef
;
29 enum class Opacity
: uint8_t { FULLY_OPAQUE
, SOME_TRANSPARENCY
};
32 typedef gfx::SourceSurfaceSharedData SourceSurfaceSharedData
;
33 typedef gfx::DrawTarget DrawTarget
;
34 typedef gfx::SamplingFilter SamplingFilter
;
35 typedef gfx::IntPoint IntPoint
;
36 typedef gfx::IntRect IntRect
;
37 typedef gfx::IntSize IntSize
;
38 typedef gfx::SourceSurface SourceSurface
;
39 typedef gfx::SurfaceFormat SurfaceFormat
;
42 MOZ_DECLARE_REFCOUNTED_TYPENAME(imgFrame
)
43 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(imgFrame
)
48 * Initialize this imgFrame with an empty surface and prepare it for being
49 * written to by a decoder.
51 * This is appropriate for use with decoded images, but it should not be used
52 * when drawing content into an imgFrame, as it may use a different graphics
53 * backend than normal content drawing.
55 nsresult
InitForDecoder(const nsIntSize
& aImageSize
, SurfaceFormat aFormat
,
57 const Maybe
<AnimationParams
>& aAnimParams
,
61 * Reinitialize this imgFrame with the new parameters, but otherwise retain
62 * the underlying buffer.
64 * This is appropriate for use with animated images, where the decoder was
65 * given an IDecoderFrameRecycler object which may yield a recycled imgFrame
66 * that was discarded to save memory.
68 nsresult
InitForDecoderRecycle(const AnimationParams
& aAnimParams
);
71 * Initialize this imgFrame with a new surface and draw the provided
72 * gfxDrawable into it.
74 * This is appropriate to use when drawing content into an imgFrame, as it
75 * uses the same graphics backend as normal content drawing. The downside is
76 * that the underlying surface may not be stored in a volatile buffer on all
77 * platforms, and raw access to the surface (using RawAccessRef()) may be much
78 * more expensive than in the InitForDecoder() case.
80 * aBackend specifies the DrawTarget backend type this imgFrame is supposed
83 nsresult
InitWithDrawable(gfxDrawable
* aDrawable
, const nsIntSize
& aSize
,
84 const SurfaceFormat aFormat
,
85 SamplingFilter aSamplingFilter
,
86 uint32_t aImageFlags
, gfx::BackendType aBackend
);
88 DrawableFrameRef
DrawableRef();
91 * Create a RawAccessFrameRef for the frame.
93 RawAccessFrameRef
RawAccessRef();
95 bool Draw(gfxContext
* aContext
, const ImageRegion
& aRegion
,
96 SamplingFilter aSamplingFilter
, uint32_t aImageFlags
,
99 nsresult
ImageUpdated(const nsIntRect
& aUpdateRect
);
102 * Mark this imgFrame as completely decoded, and set final options.
104 * You must always call either Finish() or Abort() before releasing the last
105 * RawAccessFrameRef pointing to an imgFrame.
107 * @param aFrameOpacity Whether this imgFrame is opaque.
108 * @param aFinalize Finalize the underlying surface (e.g. so that it
109 * may be marked as read only if possible).
111 void Finish(Opacity aFrameOpacity
= Opacity::SOME_TRANSPARENCY
,
112 bool aFinalize
= true,
113 bool aOrientationSwapsWidthAndHeight
= false);
116 * Mark this imgFrame as aborted. This informs the imgFrame that if it isn't
117 * completely decoded now, it never will be.
119 * You must always call either Finish() or Abort() before releasing the last
120 * RawAccessFrameRef pointing to an imgFrame.
125 * Returns true if this imgFrame has been aborted.
127 bool IsAborted() const;
130 * Returns true if this imgFrame is completely decoded.
132 bool IsFinished() const;
135 * Blocks until this imgFrame is either completely decoded, or is marked as
138 * Note that calling this on the main thread _blocks the main thread_. Be very
139 * careful in your use of this method to avoid excessive main thread jank or
142 void WaitUntilFinished() const;
145 * Returns the number of bytes per pixel this imgFrame requires.
147 uint32_t GetBytesPerPixel() const { return 4; }
149 const IntSize
& GetSize() const { return mImageSize
; }
150 IntRect
GetRect() const { return IntRect(IntPoint(0, 0), mImageSize
); }
151 const IntRect
& GetBlendRect() const { return mBlendRect
; }
152 IntRect
GetBoundedBlendRect() const {
153 return mBlendRect
.Intersect(GetRect());
155 nsIntRect
GetDecodedRect() const {
156 MonitorAutoLock
lock(mMonitor
);
159 FrameTimeout
GetTimeout() const { return mTimeout
; }
160 BlendMethod
GetBlendMethod() const { return mBlendMethod
; }
161 DisposalMethod
GetDisposalMethod() const { return mDisposalMethod
; }
162 bool FormatHasAlpha() const { return mFormat
== SurfaceFormat::OS_RGBA
; }
163 void GetImageData(uint8_t** aData
, uint32_t* length
) const;
164 uint8_t* GetImageData() const;
166 const IntRect
& GetDirtyRect() const { return mDirtyRect
; }
167 void SetDirtyRect(const IntRect
& aDirtyRect
) { mDirtyRect
= aDirtyRect
; }
169 void FinalizeSurface();
170 already_AddRefed
<SourceSurface
> GetSourceSurface();
172 struct AddSizeOfCbData
: public SourceSurface::SizeOfInfo
{
173 AddSizeOfCbData() : mIndex(0), mFinished(false) {}
179 typedef std::function
<void(AddSizeOfCbData
& aMetadata
)> AddSizeOfCb
;
181 void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf
,
182 const AddSizeOfCb
& aCallback
) const;
187 bool AreAllPixelsWritten() const MOZ_REQUIRES(mMonitor
);
188 nsresult
ImageUpdatedInternal(const nsIntRect
& aUpdateRect
);
189 void GetImageDataInternal(uint8_t** aData
, uint32_t* length
) const;
190 uint32_t GetImageBytesPerRow() const;
191 uint32_t GetImageDataLength() const;
192 void FinalizeSurfaceInternal();
193 already_AddRefed
<SourceSurface
> GetSourceSurfaceInternal();
195 struct SurfaceWithFormat
{
196 RefPtr
<gfxDrawable
> mDrawable
;
197 SurfaceFormat mFormat
;
198 SurfaceWithFormat() : mFormat(SurfaceFormat::UNKNOWN
) {}
199 SurfaceWithFormat(gfxDrawable
* aDrawable
, SurfaceFormat aFormat
)
200 : mDrawable(aDrawable
), mFormat(aFormat
) {}
201 SurfaceWithFormat(SurfaceWithFormat
&& aOther
)
202 : mDrawable(std::move(aOther
.mDrawable
)), mFormat(aOther
.mFormat
) {}
203 SurfaceWithFormat
& operator=(SurfaceWithFormat
&& aOther
) {
204 mDrawable
= std::move(aOther
.mDrawable
);
205 mFormat
= aOther
.mFormat
;
208 SurfaceWithFormat
& operator=(const SurfaceWithFormat
& aOther
) = delete;
209 SurfaceWithFormat(const SurfaceWithFormat
& aOther
) = delete;
210 bool IsValid() { return !!mDrawable
; }
213 SurfaceWithFormat
SurfaceForDrawing(bool aDoPartialDecode
, bool aDoTile
,
214 ImageRegion
& aRegion
,
215 SourceSurface
* aSurface
);
218 friend class DrawableFrameRef
;
219 friend class RawAccessFrameRef
;
220 friend class UnlockImageDataRunnable
;
222 //////////////////////////////////////////////////////////////////////////////
223 // Thread-safe mutable data, protected by mMonitor.
224 //////////////////////////////////////////////////////////////////////////////
226 mutable Monitor mMonitor
;
229 * Used for rasterized images, this contains the raw pixel data.
231 RefPtr
<SourceSurfaceSharedData
> mRawSurface
MOZ_GUARDED_BY(mMonitor
);
232 RefPtr
<SourceSurfaceSharedData
> mBlankRawSurface
MOZ_GUARDED_BY(mMonitor
);
235 * Used for vector images that were not rasterized directly. This might be a
236 * blob recording or native surface.
238 RefPtr
<SourceSurface
> mOptSurface
MOZ_GUARDED_BY(mMonitor
);
240 nsIntRect mDecoded
MOZ_GUARDED_BY(mMonitor
);
242 bool mAborted
MOZ_GUARDED_BY(mMonitor
);
243 bool mFinished
MOZ_GUARDED_BY(mMonitor
);
244 bool mShouldRecycle
MOZ_GUARDED_BY(mMonitor
);
246 //////////////////////////////////////////////////////////////////////////////
247 // Effectively const data, only mutated in the Init methods.
248 //////////////////////////////////////////////////////////////////////////////
250 //! The size of the buffer we are decoding to.
253 //! The contents for the frame, as represented in the encoded image. This may
254 //! differ from mImageSize because it may be a partial frame. For the first
255 //! frame, this means we need to shift the data in place, and for animated
256 //! frames, it likely need to combine with a previous frame to get the full
260 //! This is the region that has changed between this frame and the previous
261 //! frame of an animation. For the first frame, this will be the same as
265 //! The timeout for this frame.
266 FrameTimeout mTimeout
;
268 DisposalMethod mDisposalMethod
;
269 BlendMethod mBlendMethod
;
270 SurfaceFormat mFormat
;
276 * A reference to an imgFrame that holds the imgFrame's surface in memory,
277 * allowing drawing. If you have a DrawableFrameRef |ref| and |if (ref)| returns
278 * true, then calls to Draw() and GetSourceSurface() are guaranteed to succeed.
280 class DrawableFrameRef final
{
281 typedef gfx::DataSourceSurface DataSourceSurface
;
284 DrawableFrameRef() = default;
286 explicit DrawableFrameRef(imgFrame
* aFrame
) : mFrame(aFrame
) {
288 MonitorAutoLock
lock(aFrame
->mMonitor
);
290 if (aFrame
->mRawSurface
) {
291 mRef
.emplace(aFrame
->mRawSurface
, DataSourceSurface::READ
);
292 if (!mRef
->IsMapped()) {
296 } else if (!aFrame
->mOptSurface
|| !aFrame
->mOptSurface
->IsValid()) {
297 // The optimized surface has become invalid, so we need to redecode.
298 // For example, on Windows, there may have been a device reset, and
299 // all D2D surfaces now need to be recreated.
304 DrawableFrameRef(DrawableFrameRef
&& aOther
)
305 : mFrame(std::move(aOther
.mFrame
)), mRef(std::move(aOther
.mRef
)) {}
307 DrawableFrameRef
& operator=(DrawableFrameRef
&& aOther
) {
308 MOZ_ASSERT(this != &aOther
, "Self-moves are prohibited");
309 mFrame
= std::move(aOther
.mFrame
);
310 mRef
= std::move(aOther
.mRef
);
314 explicit operator bool() const { return bool(mFrame
); }
316 imgFrame
* operator->() {
321 const imgFrame
* operator->() const {
326 imgFrame
* get() { return mFrame
; }
327 const imgFrame
* get() const { return mFrame
; }
335 DrawableFrameRef(const DrawableFrameRef
& aOther
) = delete;
336 DrawableFrameRef
& operator=(const DrawableFrameRef
& aOther
) = delete;
338 RefPtr
<imgFrame
> mFrame
;
339 Maybe
<DataSourceSurface::ScopedMap
> mRef
;
343 * A reference to an imgFrame that holds the imgFrame's surface in memory in a
344 * format appropriate for access as raw data. If you have a RawAccessFrameRef
345 * |ref| and |if (ref)| is true, then calls to GetImageData() is guaranteed to
346 * succeed. This guarantee is stronger than DrawableFrameRef, so everything that
347 * a valid DrawableFrameRef guarantees is also guaranteed by a valid
350 * This may be considerably more expensive than is necessary just for drawing,
351 * so only use this when you need to read or write the raw underlying image data
352 * that the imgFrame holds.
354 * Once all an imgFrame's RawAccessFrameRefs go out of scope, new
355 * RawAccessFrameRefs cannot be created.
357 class RawAccessFrameRef final
{
359 RawAccessFrameRef() : mData(nullptr) {}
361 explicit RawAccessFrameRef(imgFrame
* aFrame
)
362 : mFrame(aFrame
), mData(nullptr) {
363 MOZ_ASSERT(mFrame
, "Need a frame");
365 mData
= mFrame
->GetImageData();
371 RawAccessFrameRef(RawAccessFrameRef
&& aOther
)
372 : mFrame(std::move(aOther
.mFrame
)), mData(aOther
.mData
) {
373 aOther
.mData
= nullptr;
376 ~RawAccessFrameRef() = default;
378 RawAccessFrameRef
& operator=(RawAccessFrameRef
&& aOther
) {
379 MOZ_ASSERT(this != &aOther
, "Self-moves are prohibited");
381 mFrame
= std::move(aOther
.mFrame
);
382 mData
= aOther
.mData
;
383 aOther
.mData
= nullptr;
388 explicit operator bool() const { return bool(mFrame
); }
390 imgFrame
* operator->() {
395 const imgFrame
* operator->() const {
400 imgFrame
* get() { return mFrame
; }
401 const imgFrame
* get() const { return mFrame
; }
408 uint8_t* Data() const { return mData
; }
411 RawAccessFrameRef(const RawAccessFrameRef
& aOther
) = delete;
412 RawAccessFrameRef
& operator=(const RawAccessFrameRef
& aOther
) = delete;
414 RefPtr
<imgFrame
> mFrame
;
419 } // namespace mozilla
421 #endif // mozilla_image_imgFrame_h