Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / image / imgFrame.h
blob8ce0d4bf2c14527766fad4e99895f1e541c57de5
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,
59 uint32_t* aImageDataLength = nullptr);
61 /**
62 * Reinitialize this imgFrame with the new parameters, but otherwise retain
63 * the underlying buffer.
65 * This is appropriate for use with animated images, where the decoder was
66 * given an IDecoderFrameRecycler object which may yield a recycled imgFrame
67 * that was discarded to save memory.
69 nsresult InitForDecoderRecycle(const AnimationParams& aAnimParams,
70 uint32_t* aImageDataLength = nullptr);
72 /**
73 * Initialize this imgFrame with a new surface and draw the provided
74 * gfxDrawable into it.
76 * This is appropriate to use when drawing content into an imgFrame, as it
77 * uses the same graphics backend as normal content drawing. The downside is
78 * that the underlying surface may not be stored in a volatile buffer on all
79 * platforms, and raw access to the surface (using RawAccessRef()) may be much
80 * more expensive than in the InitForDecoder() case.
82 * aBackend specifies the DrawTarget backend type this imgFrame is supposed
83 * to be drawn to.
85 nsresult InitWithDrawable(gfxDrawable* aDrawable, const nsIntSize& aSize,
86 const SurfaceFormat aFormat,
87 SamplingFilter aSamplingFilter,
88 uint32_t aImageFlags, gfx::BackendType aBackend);
90 DrawableFrameRef DrawableRef();
92 /**
93 * Create a RawAccessFrameRef for the frame.
95 RawAccessFrameRef RawAccessRef(
96 gfx::DataSourceSurface::MapType aMapType = gfx::DataSourceSurface::READ);
98 bool Draw(gfxContext* aContext, const ImageRegion& aRegion,
99 SamplingFilter aSamplingFilter, uint32_t aImageFlags,
100 float aOpacity);
102 nsresult ImageUpdated(const nsIntRect& aUpdateRect);
105 * Mark this imgFrame as completely decoded, and set final options.
107 * You must always call either Finish() or Abort() before releasing the last
108 * RawAccessFrameRef pointing to an imgFrame.
110 * @param aFrameOpacity Whether this imgFrame is opaque.
111 * @param aFinalize Finalize the underlying surface (e.g. so that it
112 * may be marked as read only if possible).
114 void Finish(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
115 bool aFinalize = true,
116 bool aOrientationSwapsWidthAndHeight = false);
119 * Mark this imgFrame as aborted. This informs the imgFrame that if it isn't
120 * completely decoded now, it never will be.
122 * You must always call either Finish() or Abort() before releasing the last
123 * RawAccessFrameRef pointing to an imgFrame.
125 void Abort();
128 * Returns true if this imgFrame has been aborted.
130 bool IsAborted() const;
133 * Returns true if this imgFrame is completely decoded.
135 bool IsFinished() const;
138 * Blocks until this imgFrame is either completely decoded, or is marked as
139 * aborted.
141 * Note that calling this on the main thread _blocks the main thread_. Be very
142 * careful in your use of this method to avoid excessive main thread jank or
143 * deadlock.
145 void WaitUntilFinished() const;
148 * Returns the number of bytes per pixel this imgFrame requires.
150 uint32_t GetBytesPerPixel() const { return 4; }
152 const IntSize& GetSize() const { return mImageSize; }
153 IntRect GetRect() const { return IntRect(IntPoint(0, 0), mImageSize); }
154 const IntRect& GetBlendRect() const { return mBlendRect; }
155 IntRect GetBoundedBlendRect() const {
156 return mBlendRect.Intersect(GetRect());
158 nsIntRect GetDecodedRect() const {
159 MonitorAutoLock lock(mMonitor);
160 return mDecoded;
162 FrameTimeout GetTimeout() const { return mTimeout; }
163 BlendMethod GetBlendMethod() const { return mBlendMethod; }
164 DisposalMethod GetDisposalMethod() const { return mDisposalMethod; }
165 bool FormatHasAlpha() const { return mFormat == SurfaceFormat::OS_RGBA; }
167 const IntRect& GetDirtyRect() const { return mDirtyRect; }
168 void SetDirtyRect(const IntRect& aDirtyRect) { mDirtyRect = aDirtyRect; }
170 void FinalizeSurface();
171 already_AddRefed<SourceSurface> GetSourceSurface();
173 struct AddSizeOfCbData : public SourceSurface::SizeOfInfo {
174 AddSizeOfCbData() : mIndex(0), mFinished(false) {}
176 size_t mIndex;
177 bool mFinished;
180 typedef std::function<void(AddSizeOfCbData& aMetadata)> AddSizeOfCb;
182 void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
183 const AddSizeOfCb& aCallback) const;
185 private: // methods
186 ~imgFrame();
188 bool AreAllPixelsWritten() const MOZ_REQUIRES(mMonitor);
189 nsresult ImageUpdatedInternal(const nsIntRect& aUpdateRect);
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;
206 return *this;
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);
217 private: // data
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.
251 IntSize mImageSize;
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
257 //! contents.
258 IntRect mBlendRect;
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
262 //! mFrameRect.
263 IntRect mDirtyRect;
265 //! The timeout for this frame.
266 FrameTimeout mTimeout;
268 DisposalMethod mDisposalMethod;
269 BlendMethod mBlendMethod;
270 SurfaceFormat mFormat;
272 bool mNonPremult;
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;
283 public:
284 DrawableFrameRef() = default;
286 explicit DrawableFrameRef(imgFrame* aFrame) : mFrame(aFrame) {
287 MOZ_ASSERT(aFrame);
288 MonitorAutoLock lock(aFrame->mMonitor);
290 if (aFrame->mRawSurface) {
291 mRef.emplace(aFrame->mRawSurface, DataSourceSurface::READ);
292 if (!mRef->IsMapped()) {
293 mFrame = nullptr;
294 mRef.reset();
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.
300 mFrame = nullptr;
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);
311 return *this;
314 explicit operator bool() const { return bool(mFrame); }
316 imgFrame* operator->() {
317 MOZ_ASSERT(mFrame);
318 return mFrame;
321 const imgFrame* operator->() const {
322 MOZ_ASSERT(mFrame);
323 return mFrame;
326 imgFrame* get() { return mFrame; }
327 const imgFrame* get() const { return mFrame; }
329 void reset() {
330 mFrame = nullptr;
331 mRef.reset();
334 private:
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
348 * RawAccessFrameRef.
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 {
358 public:
359 RawAccessFrameRef() = default;
361 explicit RawAccessFrameRef(imgFrame* aFrame,
362 gfx::DataSourceSurface::MapType aMapType)
363 : mFrame(aFrame) {
364 MOZ_ASSERT(mFrame, "Need a frame");
366 // Note that we do not use ScopedMap here because it holds a strong
367 // reference to the underlying surface. This affects the reuse logic for
368 // recycling in imgFrame::InitForDecoderRecycle.
370 MonitorAutoLock lock(mFrame->mMonitor);
371 gfx::DataSourceSurface::MappedSurface map;
372 if (mFrame->mRawSurface && mFrame->mRawSurface->Map(aMapType, &map)) {
373 MOZ_ASSERT(map.mData);
374 mData = map.mData;
378 if (!mData) {
379 mFrame = nullptr;
383 RawAccessFrameRef(RawAccessFrameRef&& aOther)
384 : mFrame(std::move(aOther.mFrame)), mData(aOther.mData) {
385 aOther.mData = nullptr;
388 ~RawAccessFrameRef() { reset(); }
390 RawAccessFrameRef& operator=(RawAccessFrameRef&& aOther) {
391 MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
393 if (mFrame) {
394 MonitorAutoLock lock(mFrame->mMonitor);
395 mFrame->mRawSurface->Unmap();
397 mFrame = std::move(aOther.mFrame);
398 mData = aOther.mData;
399 aOther.mData = nullptr;
401 return *this;
404 explicit operator bool() const { return bool(mFrame); }
406 imgFrame* operator->() {
407 MOZ_ASSERT(mFrame);
408 return mFrame.get();
411 const imgFrame* operator->() const {
412 MOZ_ASSERT(mFrame);
413 return mFrame;
416 imgFrame* get() { return mFrame; }
417 const imgFrame* get() const { return mFrame; }
419 void reset() {
420 if (mFrame) {
421 MonitorAutoLock lock(mFrame->mMonitor);
422 mFrame->mRawSurface->Unmap();
424 mFrame = nullptr;
425 mData = nullptr;
428 uint8_t* Data() const { return mData; }
430 private:
431 RawAccessFrameRef(const RawAccessFrameRef& aOther) = delete;
432 RawAccessFrameRef& operator=(const RawAccessFrameRef& aOther) = delete;
434 RefPtr<imgFrame> mFrame;
435 uint8_t* mData = nullptr;
438 } // namespace image
439 } // namespace mozilla
441 #endif // mozilla_image_imgFrame_h