Bug 1736711 [wpt PR 31319] - [@layer] Make 'revert-layer' work in keyframes, a=testonly
[gecko.git] / image / imgFrame.h
blob9851e211881d73c2677791c329cf7874e80f6a73
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 <functional>
11 #include <utility>
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"
20 #include "nsRect.h"
22 namespace mozilla {
23 namespace image {
25 class ImageRegion;
26 class DrawableFrameRef;
27 class RawAccessFrameRef;
29 enum class Opacity : uint8_t { FULLY_OPAQUE, SOME_TRANSPARENCY };
31 class imgFrame {
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;
41 public:
42 MOZ_DECLARE_REFCOUNTED_TYPENAME(imgFrame)
43 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(imgFrame)
45 imgFrame();
47 /**
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,
56 bool aNonPremult,
57 const Maybe<AnimationParams>& aAnimParams,
58 bool aShouldRecycle);
60 /**
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);
70 /**
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
81 * to be drawn to.
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();
90 /**
91 * Create a RawAccessFrameRef for the frame.
93 RawAccessFrameRef RawAccessRef();
95 bool Draw(gfxContext* aContext, const ImageRegion& aRegion,
96 SamplingFilter aSamplingFilter, uint32_t aImageFlags,
97 float aOpacity);
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);
115 * Mark this imgFrame as aborted. This informs the imgFrame that if it isn't
116 * completely decoded now, it never will be.
118 * You must always call either Finish() or Abort() before releasing the last
119 * RawAccessFrameRef pointing to an imgFrame.
121 void Abort();
124 * Returns true if this imgFrame has been aborted.
126 bool IsAborted() const;
129 * Returns true if this imgFrame is completely decoded.
131 bool IsFinished() const;
134 * Blocks until this imgFrame is either completely decoded, or is marked as
135 * aborted.
137 * Note that calling this on the main thread _blocks the main thread_. Be very
138 * careful in your use of this method to avoid excessive main thread jank or
139 * deadlock.
141 void WaitUntilFinished() const;
144 * Returns the number of bytes per pixel this imgFrame requires.
146 uint32_t GetBytesPerPixel() const { return 4; }
148 const IntSize& GetSize() const { return mImageSize; }
149 IntRect GetRect() const { return IntRect(IntPoint(0, 0), mImageSize); }
150 const IntRect& GetBlendRect() const { return mBlendRect; }
151 IntRect GetBoundedBlendRect() const {
152 return mBlendRect.Intersect(GetRect());
154 FrameTimeout GetTimeout() const { return mTimeout; }
155 BlendMethod GetBlendMethod() const { return mBlendMethod; }
156 DisposalMethod GetDisposalMethod() const { return mDisposalMethod; }
157 bool FormatHasAlpha() const { return mFormat == SurfaceFormat::OS_RGBA; }
158 void GetImageData(uint8_t** aData, uint32_t* length) const;
159 uint8_t* GetImageData() const;
161 const IntRect& GetDirtyRect() const { return mDirtyRect; }
162 void SetDirtyRect(const IntRect& aDirtyRect) { mDirtyRect = aDirtyRect; }
164 void FinalizeSurface();
165 already_AddRefed<SourceSurface> GetSourceSurface();
167 struct AddSizeOfCbData : public SourceSurface::SizeOfInfo {
168 AddSizeOfCbData()
169 : SourceSurface::SizeOfInfo(), mIndex(0), mFinished(false) {}
171 const gfx::SourceSurface* mSurface;
172 size_t mIndex;
173 bool mFinished;
176 typedef std::function<void(AddSizeOfCbData& aMetadata)> AddSizeOfCb;
178 void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
179 const AddSizeOfCb& aCallback) const;
181 private: // methods
182 ~imgFrame();
184 bool AreAllPixelsWritten() const;
185 nsresult ImageUpdatedInternal(const nsIntRect& aUpdateRect);
186 void GetImageDataInternal(uint8_t** aData, uint32_t* length) const;
187 uint32_t GetImageBytesPerRow() const;
188 uint32_t GetImageDataLength() const;
189 void FinalizeSurfaceInternal();
190 already_AddRefed<SourceSurface> GetSourceSurfaceInternal();
192 struct SurfaceWithFormat {
193 RefPtr<gfxDrawable> mDrawable;
194 SurfaceFormat mFormat;
195 SurfaceWithFormat() : mFormat(SurfaceFormat::UNKNOWN) {}
196 SurfaceWithFormat(gfxDrawable* aDrawable, SurfaceFormat aFormat)
197 : mDrawable(aDrawable), mFormat(aFormat) {}
198 SurfaceWithFormat(SurfaceWithFormat&& aOther)
199 : mDrawable(std::move(aOther.mDrawable)), mFormat(aOther.mFormat) {}
200 SurfaceWithFormat& operator=(SurfaceWithFormat&& aOther) {
201 mDrawable = std::move(aOther.mDrawable);
202 mFormat = aOther.mFormat;
203 return *this;
205 SurfaceWithFormat& operator=(const SurfaceWithFormat& aOther) = delete;
206 SurfaceWithFormat(const SurfaceWithFormat& aOther) = delete;
207 bool IsValid() { return !!mDrawable; }
210 SurfaceWithFormat SurfaceForDrawing(bool aDoPartialDecode, bool aDoTile,
211 ImageRegion& aRegion,
212 SourceSurface* aSurface);
214 private: // data
215 friend class DrawableFrameRef;
216 friend class RawAccessFrameRef;
217 friend class UnlockImageDataRunnable;
219 //////////////////////////////////////////////////////////////////////////////
220 // Thread-safe mutable data, protected by mMonitor.
221 //////////////////////////////////////////////////////////////////////////////
223 mutable Monitor mMonitor;
226 * Used for rasterized images, this contains the raw pixel data.
228 RefPtr<SourceSurfaceSharedData> mRawSurface;
229 RefPtr<SourceSurfaceSharedData> mBlankRawSurface;
232 * Used for vector images that were not rasterized directly. This might be a
233 * blob recording or native surface.
235 RefPtr<SourceSurface> mOptSurface;
237 nsIntRect mDecoded;
239 bool mAborted;
240 bool mFinished;
241 bool mShouldRecycle;
243 //////////////////////////////////////////////////////////////////////////////
244 // Effectively const data, only mutated in the Init methods.
245 //////////////////////////////////////////////////////////////////////////////
247 //! The size of the buffer we are decoding to.
248 IntSize mImageSize;
250 //! The contents for the frame, as represented in the encoded image. This may
251 //! differ from mImageSize because it may be a partial frame. For the first
252 //! frame, this means we need to shift the data in place, and for animated
253 //! frames, it likely need to combine with a previous frame to get the full
254 //! contents.
255 IntRect mBlendRect;
257 //! This is the region that has changed between this frame and the previous
258 //! frame of an animation. For the first frame, this will be the same as
259 //! mFrameRect.
260 IntRect mDirtyRect;
262 //! The timeout for this frame.
263 FrameTimeout mTimeout;
265 DisposalMethod mDisposalMethod;
266 BlendMethod mBlendMethod;
267 SurfaceFormat mFormat;
269 bool mNonPremult;
273 * A reference to an imgFrame that holds the imgFrame's surface in memory,
274 * allowing drawing. If you have a DrawableFrameRef |ref| and |if (ref)| returns
275 * true, then calls to Draw() and GetSourceSurface() are guaranteed to succeed.
277 class DrawableFrameRef final {
278 typedef gfx::DataSourceSurface DataSourceSurface;
280 public:
281 DrawableFrameRef() {}
283 explicit DrawableFrameRef(imgFrame* aFrame) : mFrame(aFrame) {
284 MOZ_ASSERT(aFrame);
285 MonitorAutoLock lock(aFrame->mMonitor);
287 if (aFrame->mRawSurface) {
288 mRef.emplace(aFrame->mRawSurface, DataSourceSurface::READ);
289 if (!mRef->IsMapped()) {
290 mFrame = nullptr;
291 mRef.reset();
293 } else if (!aFrame->mOptSurface || !aFrame->mOptSurface->IsValid()) {
294 // The optimized surface has become invalid, so we need to redecode.
295 // For example, on Windows, there may have been a device reset, and
296 // all D2D surfaces now need to be recreated.
297 mFrame = nullptr;
301 DrawableFrameRef(DrawableFrameRef&& aOther)
302 : mFrame(std::move(aOther.mFrame)), mRef(std::move(aOther.mRef)) {}
304 DrawableFrameRef& operator=(DrawableFrameRef&& aOther) {
305 MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
306 mFrame = std::move(aOther.mFrame);
307 mRef = std::move(aOther.mRef);
308 return *this;
311 explicit operator bool() const { return bool(mFrame); }
313 imgFrame* operator->() {
314 MOZ_ASSERT(mFrame);
315 return mFrame;
318 const imgFrame* operator->() const {
319 MOZ_ASSERT(mFrame);
320 return mFrame;
323 imgFrame* get() { return mFrame; }
324 const imgFrame* get() const { return mFrame; }
326 void reset() {
327 mFrame = nullptr;
328 mRef.reset();
331 private:
332 DrawableFrameRef(const DrawableFrameRef& aOther) = delete;
333 DrawableFrameRef& operator=(const DrawableFrameRef& aOther) = delete;
335 RefPtr<imgFrame> mFrame;
336 Maybe<DataSourceSurface::ScopedMap> mRef;
340 * A reference to an imgFrame that holds the imgFrame's surface in memory in a
341 * format appropriate for access as raw data. If you have a RawAccessFrameRef
342 * |ref| and |if (ref)| is true, then calls to GetImageData() is guaranteed to
343 * succeed. This guarantee is stronger than DrawableFrameRef, so everything that
344 * a valid DrawableFrameRef guarantees is also guaranteed by a valid
345 * RawAccessFrameRef.
347 * This may be considerably more expensive than is necessary just for drawing,
348 * so only use this when you need to read or write the raw underlying image data
349 * that the imgFrame holds.
351 * Once all an imgFrame's RawAccessFrameRefs go out of scope, new
352 * RawAccessFrameRefs cannot be created.
354 class RawAccessFrameRef final {
355 public:
356 RawAccessFrameRef() : mData(nullptr) {}
358 explicit RawAccessFrameRef(imgFrame* aFrame)
359 : mFrame(aFrame), mData(nullptr) {
360 MOZ_ASSERT(mFrame, "Need a frame");
362 mData = mFrame->GetImageData();
363 if (!mData) {
364 mFrame = nullptr;
368 RawAccessFrameRef(RawAccessFrameRef&& aOther)
369 : mFrame(std::move(aOther.mFrame)), mData(aOther.mData) {
370 aOther.mData = nullptr;
373 ~RawAccessFrameRef() {}
375 RawAccessFrameRef& operator=(RawAccessFrameRef&& aOther) {
376 MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
378 mFrame = std::move(aOther.mFrame);
379 mData = aOther.mData;
380 aOther.mData = nullptr;
382 return *this;
385 explicit operator bool() const { return bool(mFrame); }
387 imgFrame* operator->() {
388 MOZ_ASSERT(mFrame);
389 return mFrame.get();
392 const imgFrame* operator->() const {
393 MOZ_ASSERT(mFrame);
394 return mFrame;
397 imgFrame* get() { return mFrame; }
398 const imgFrame* get() const { return mFrame; }
400 void reset() {
401 mFrame = nullptr;
402 mData = nullptr;
405 uint8_t* Data() const { return mData; }
407 private:
408 RawAccessFrameRef(const RawAccessFrameRef& aOther) = delete;
409 RawAccessFrameRef& operator=(const RawAccessFrameRef& aOther) = delete;
411 RefPtr<imgFrame> mFrame;
412 uint8_t* mData;
415 } // namespace image
416 } // namespace mozilla
418 #endif // mozilla_image_imgFrame_h