Bug 1610357 [wpt PR 21278] - Update wpt metadata, a=testonly
[gecko.git] / image / imgFrame.h
blobdb6b704aa49b78e39b664c04629ed6053112dac9
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 <utility>
12 #include "AnimationParams.h"
13 #include "MainThreadUtils.h"
14 #include "gfxDrawable.h"
15 #include "mozilla/Maybe.h"
16 #include "mozilla/MemoryReporting.h"
17 #include "mozilla/Monitor.h"
19 namespace mozilla {
20 namespace image {
22 class ImageRegion;
23 class DrawableFrameRef;
24 class RawAccessFrameRef;
26 enum class Opacity : uint8_t { FULLY_OPAQUE, SOME_TRANSPARENCY };
28 class imgFrame {
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;
39 public:
40 MOZ_DECLARE_REFCOUNTED_TYPENAME(imgFrame)
41 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(imgFrame)
43 imgFrame();
45 /**
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,
54 bool aNonPremult,
55 const Maybe<AnimationParams>& aAnimParams,
56 bool aShouldRecycle);
58 /**
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);
68 /**
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
79 * to be drawn to.
81 nsresult InitWithDrawable(gfxDrawable* aDrawable, const nsIntSize& aSize,
82 const SurfaceFormat aFormat,
83 SamplingFilter aSamplingFilter,
84 uint32_t aImageFlags, gfx::BackendType aBackend);
86 DrawableFrameRef DrawableRef();
88 /**
89 * Create a RawAccessFrameRef for the frame.
91 * @param aOnlyFinished If true, only return a valid RawAccessFrameRef if
92 * imgFrame::Finish has been called.
94 RawAccessFrameRef RawAccessRef(bool aOnlyFinished = false);
96 /**
97 * Make this imgFrame permanently available for raw access.
99 * This is irrevocable, and should be avoided whenever possible, since it
100 * prevents this imgFrame from being optimized and makes it impossible for its
101 * volatile buffer to be freed.
103 * It is an error to call this without already holding a RawAccessFrameRef to
104 * this imgFrame.
106 void SetRawAccessOnly();
108 bool Draw(gfxContext* aContext, const ImageRegion& aRegion,
109 SamplingFilter aSamplingFilter, uint32_t aImageFlags,
110 float aOpacity);
112 nsresult ImageUpdated(const nsIntRect& aUpdateRect);
115 * Mark this imgFrame as completely decoded, and set final options.
117 * You must always call either Finish() or Abort() before releasing the last
118 * RawAccessFrameRef pointing to an imgFrame.
120 * @param aFrameOpacity Whether this imgFrame is opaque.
121 * @param aFinalize Finalize the underlying surface (e.g. so that it
122 * may be marked as read only if possible).
124 void Finish(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
125 bool aFinalize = true);
128 * Mark this imgFrame as aborted. This informs the imgFrame that if it isn't
129 * completely decoded now, it never will be.
131 * You must always call either Finish() or Abort() before releasing the last
132 * RawAccessFrameRef pointing to an imgFrame.
134 void Abort();
137 * Returns true if this imgFrame has been aborted.
139 bool IsAborted() const;
142 * Returns true if this imgFrame is completely decoded.
144 bool IsFinished() const;
147 * Blocks until this imgFrame is either completely decoded, or is marked as
148 * aborted.
150 * Note that calling this on the main thread _blocks the main thread_. Be very
151 * careful in your use of this method to avoid excessive main thread jank or
152 * deadlock.
154 void WaitUntilFinished() const;
157 * Returns the number of bytes per pixel this imgFrame requires. This is a
158 * worst-case value that does not take into account the effects of format
159 * changes caused by Optimize(), since an imgFrame is not optimized throughout
160 * its lifetime.
162 uint32_t GetBytesPerPixel() const { return 4; }
164 const IntSize& GetSize() const { return mImageSize; }
165 IntRect GetRect() const { return IntRect(IntPoint(0, 0), mImageSize); }
166 const IntRect& GetBlendRect() const { return mBlendRect; }
167 IntRect GetBoundedBlendRect() const {
168 return mBlendRect.Intersect(GetRect());
170 FrameTimeout GetTimeout() const { return mTimeout; }
171 BlendMethod GetBlendMethod() const { return mBlendMethod; }
172 DisposalMethod GetDisposalMethod() const { return mDisposalMethod; }
173 bool FormatHasAlpha() const { return mFormat == SurfaceFormat::OS_RGBA; }
174 void GetImageData(uint8_t** aData, uint32_t* length) const;
175 uint8_t* GetImageData() const;
177 const IntRect& GetDirtyRect() const { return mDirtyRect; }
178 void SetDirtyRect(const IntRect& aDirtyRect) { mDirtyRect = aDirtyRect; }
180 void SetOptimizable();
182 void FinalizeSurface();
183 already_AddRefed<SourceSurface> GetSourceSurface();
185 struct AddSizeOfCbData {
186 AddSizeOfCbData()
187 : heap(0),
188 nonHeap(0),
189 handles(0),
190 index(0),
191 externalId(0),
192 finished(false) {}
194 size_t heap;
195 size_t nonHeap;
196 size_t handles;
197 size_t index;
198 uint64_t externalId;
199 bool finished;
202 typedef std::function<void(AddSizeOfCbData& aMetadata)> AddSizeOfCb;
204 void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
205 const AddSizeOfCb& aCallback) const;
207 private: // methods
208 ~imgFrame();
211 * Used when the caller desires raw access to the underlying frame buffer.
212 * If the locking succeeds, the data pointer to the start of the buffer is
213 * returned, else it returns nullptr.
215 * @param aOnlyFinished If true, only attempt to lock if imgFrame::Finish has
216 * been called.
218 uint8_t* LockImageData(bool aOnlyFinished);
219 nsresult UnlockImageData();
220 nsresult Optimize(gfx::DrawTarget* aTarget);
222 void AssertImageDataLocked() const;
224 bool AreAllPixelsWritten() const;
225 nsresult ImageUpdatedInternal(const nsIntRect& aUpdateRect);
226 void GetImageDataInternal(uint8_t** aData, uint32_t* length) const;
227 uint32_t GetImageBytesPerRow() const;
228 uint32_t GetImageDataLength() const;
229 void FinalizeSurfaceInternal();
232 * @param aTemporary If true, it will assume the caller does not require a
233 * wrapping RecycleSourceSurface to protect the underlying
234 * surface from recycling. The reference to the surface
235 * must be freed before releasing the main thread context.
237 already_AddRefed<SourceSurface> GetSourceSurfaceInternal(bool aTemporary);
239 struct SurfaceWithFormat {
240 RefPtr<gfxDrawable> mDrawable;
241 SurfaceFormat mFormat;
242 SurfaceWithFormat() : mFormat(SurfaceFormat::UNKNOWN) {}
243 SurfaceWithFormat(gfxDrawable* aDrawable, SurfaceFormat aFormat)
244 : mDrawable(aDrawable), mFormat(aFormat) {}
245 SurfaceWithFormat(SurfaceWithFormat&& aOther)
246 : mDrawable(std::move(aOther.mDrawable)), mFormat(aOther.mFormat) {}
247 SurfaceWithFormat& operator=(SurfaceWithFormat&& aOther) {
248 mDrawable = std::move(aOther.mDrawable);
249 mFormat = aOther.mFormat;
250 return *this;
252 SurfaceWithFormat& operator=(const SurfaceWithFormat& aOther) = delete;
253 SurfaceWithFormat(const SurfaceWithFormat& aOther) = delete;
254 bool IsValid() { return !!mDrawable; }
257 SurfaceWithFormat SurfaceForDrawing(bool aDoPartialDecode, bool aDoTile,
258 ImageRegion& aRegion,
259 SourceSurface* aSurface);
261 private: // data
262 friend class DrawableFrameRef;
263 friend class RawAccessFrameRef;
264 friend class RecyclingSourceSurface;
265 friend class UnlockImageDataRunnable;
267 //////////////////////////////////////////////////////////////////////////////
268 // Thread-safe mutable data, protected by mMonitor.
269 //////////////////////////////////////////////////////////////////////////////
271 mutable Monitor mMonitor;
274 * Surface which contains either a weak or a strong reference to its
275 * underlying data buffer. If it is a weak reference, and there are no strong
276 * references, the buffer may be released due to events such as low memory.
278 RefPtr<DataSourceSurface> mRawSurface;
279 RefPtr<DataSourceSurface> mBlankRawSurface;
282 * Refers to the same data as mRawSurface, but when set, it guarantees that
283 * we hold a strong reference to the underlying data buffer.
285 RefPtr<DataSourceSurface> mLockedSurface;
286 RefPtr<DataSourceSurface> mBlankLockedSurface;
289 * Optimized copy of mRawSurface for the DrawTarget that will render it. This
290 * is unused if the DrawTarget is able to render DataSourceSurface buffers
291 * directly.
293 RefPtr<SourceSurface> mOptSurface;
295 nsIntRect mDecoded;
297 //! Number of RawAccessFrameRefs currently alive for this imgFrame.
298 int16_t mLockCount;
300 //! Number of RecyclingSourceSurface's currently alive for this imgFrame.
301 int16_t mRecycleLockCount;
303 bool mAborted;
304 bool mFinished;
305 bool mOptimizable;
306 bool mShouldRecycle;
308 //////////////////////////////////////////////////////////////////////////////
309 // Effectively const data, only mutated in the Init methods.
310 //////////////////////////////////////////////////////////////////////////////
312 //! The size of the buffer we are decoding to.
313 IntSize mImageSize;
315 //! The contents for the frame, as represented in the encoded image. This may
316 //! differ from mImageSize because it may be a partial frame. For the first
317 //! frame, this means we need to shift the data in place, and for animated
318 //! frames, it likely need to combine with a previous frame to get the full
319 //! contents.
320 IntRect mBlendRect;
322 //! This is the region that has changed between this frame and the previous
323 //! frame of an animation. For the first frame, this will be the same as
324 //! mFrameRect.
325 IntRect mDirtyRect;
327 //! The timeout for this frame.
328 FrameTimeout mTimeout;
330 DisposalMethod mDisposalMethod;
331 BlendMethod mBlendMethod;
332 SurfaceFormat mFormat;
334 bool mNonPremult;
338 * A reference to an imgFrame that holds the imgFrame's surface in memory,
339 * allowing drawing. If you have a DrawableFrameRef |ref| and |if (ref)| returns
340 * true, then calls to Draw() and GetSourceSurface() are guaranteed to succeed.
342 class DrawableFrameRef final {
343 typedef gfx::DataSourceSurface DataSourceSurface;
345 public:
346 DrawableFrameRef() {}
348 explicit DrawableFrameRef(imgFrame* aFrame) : mFrame(aFrame) {
349 MOZ_ASSERT(aFrame);
350 MonitorAutoLock lock(aFrame->mMonitor);
352 if (aFrame->mRawSurface) {
353 mRef.emplace(aFrame->mRawSurface, DataSourceSurface::READ);
354 if (!mRef->IsMapped()) {
355 mFrame = nullptr;
356 mRef.reset();
358 } else if (!aFrame->mOptSurface || !aFrame->mOptSurface->IsValid()) {
359 // The optimized surface has become invalid, so we need to redecode.
360 // For example, on Windows, there may have been a device reset, and
361 // all D2D surfaces now need to be recreated.
362 mFrame = nullptr;
366 DrawableFrameRef(DrawableFrameRef&& aOther)
367 : mFrame(aOther.mFrame.forget()), mRef(std::move(aOther.mRef)) {}
369 DrawableFrameRef& operator=(DrawableFrameRef&& aOther) {
370 MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
371 mFrame = aOther.mFrame.forget();
372 mRef = std::move(aOther.mRef);
373 return *this;
376 explicit operator bool() const { return bool(mFrame); }
378 imgFrame* operator->() {
379 MOZ_ASSERT(mFrame);
380 return mFrame;
383 const imgFrame* operator->() const {
384 MOZ_ASSERT(mFrame);
385 return mFrame;
388 imgFrame* get() { return mFrame; }
389 const imgFrame* get() const { return mFrame; }
391 void reset() {
392 mFrame = nullptr;
393 mRef.reset();
396 private:
397 DrawableFrameRef(const DrawableFrameRef& aOther) = delete;
398 DrawableFrameRef& operator=(const DrawableFrameRef& aOther) = delete;
400 RefPtr<imgFrame> mFrame;
401 Maybe<DataSourceSurface::ScopedMap> mRef;
405 * A reference to an imgFrame that holds the imgFrame's surface in memory in a
406 * format appropriate for access as raw data. If you have a RawAccessFrameRef
407 * |ref| and |if (ref)| is true, then calls to GetImageData() is guaranteed to
408 * succeed. This guarantee is stronger than DrawableFrameRef, so everything that
409 * a valid DrawableFrameRef guarantees is also guaranteed by a valid
410 * RawAccessFrameRef.
412 * This may be considerably more expensive than is necessary just for drawing,
413 * so only use this when you need to read or write the raw underlying image data
414 * that the imgFrame holds.
416 * Once all an imgFrame's RawAccessFrameRefs go out of scope, new
417 * RawAccessFrameRefs cannot be created.
419 class RawAccessFrameRef final {
420 public:
421 RawAccessFrameRef() : mData(nullptr) {}
423 explicit RawAccessFrameRef(imgFrame* aFrame, bool aOnlyFinished)
424 : mFrame(aFrame), mData(nullptr) {
425 MOZ_ASSERT(mFrame, "Need a frame");
427 mData = mFrame->LockImageData(aOnlyFinished);
428 if (!mData) {
429 mFrame = nullptr;
433 RawAccessFrameRef(RawAccessFrameRef&& aOther)
434 : mFrame(aOther.mFrame.forget()), mData(aOther.mData) {
435 aOther.mData = nullptr;
438 ~RawAccessFrameRef() {
439 if (mFrame) {
440 mFrame->UnlockImageData();
444 RawAccessFrameRef& operator=(RawAccessFrameRef&& aOther) {
445 MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
447 if (mFrame) {
448 mFrame->UnlockImageData();
451 mFrame = aOther.mFrame.forget();
452 mData = aOther.mData;
453 aOther.mData = nullptr;
455 return *this;
458 explicit operator bool() const { return bool(mFrame); }
460 imgFrame* operator->() {
461 MOZ_ASSERT(mFrame);
462 return mFrame.get();
465 const imgFrame* operator->() const {
466 MOZ_ASSERT(mFrame);
467 return mFrame;
470 imgFrame* get() { return mFrame; }
471 const imgFrame* get() const { return mFrame; }
473 void reset() {
474 if (mFrame) {
475 mFrame->UnlockImageData();
477 mFrame = nullptr;
478 mData = nullptr;
481 uint8_t* Data() const { return mData; }
483 private:
484 RawAccessFrameRef(const RawAccessFrameRef& aOther) = delete;
485 RawAccessFrameRef& operator=(const RawAccessFrameRef& aOther) = delete;
487 RefPtr<imgFrame> mFrame;
488 uint8_t* mData;
491 } // namespace image
492 } // namespace mozilla
494 #endif // mozilla_image_imgFrame_h