Bug 1526591 - Remove devtools.inspector.shapesHighlighter.enabled pref. r=rcaliman
[gecko.git] / image / imgFrame.h
blob0df12b6b2658df093a8fb0e0e603644db4060dec
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"
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, const nsIntRect& aRect,
54 SurfaceFormat aFormat, uint8_t aPaletteDepth,
55 bool aNonPremult,
56 const Maybe<AnimationParams>& aAnimParams,
57 bool aIsFullFrame, bool aShouldRecycle);
59 nsresult InitForAnimator(const nsIntSize& aSize, SurfaceFormat aFormat) {
60 nsIntRect frameRect(0, 0, aSize.width, aSize.height);
61 AnimationParams animParams{frameRect, FrameTimeout::Forever(),
62 /* aFrameNum */ 1, BlendMethod::OVER,
63 DisposalMethod::NOT_SPECIFIED};
64 // We set aIsFullFrame to false because we don't want the compositing frame
65 // to be allocated into shared memory for WebRender. mIsFullFrame is only
66 // otherwise used for frames produced by Decoder, so it isn't relevant.
67 return InitForDecoder(aSize, frameRect, aFormat, /* aPaletteDepth */ 0,
68 /* aNonPremult */ false, Some(animParams),
69 /* aIsFullFrame */ false, /* aShouldRecycle */ false);
72 /**
73 * Reinitialize this imgFrame with the new parameters, but otherwise retain
74 * the underlying buffer.
76 * This is appropriate for use with animated images, where the decoder was
77 * given an IDecoderFrameRecycler object which may yield a recycled imgFrame
78 * that was discarded to save memory.
80 nsresult InitForDecoderRecycle(const AnimationParams& aAnimParams);
82 /**
83 * Initialize this imgFrame with a new surface and draw the provided
84 * gfxDrawable into it.
86 * This is appropriate to use when drawing content into an imgFrame, as it
87 * uses the same graphics backend as normal content drawing. The downside is
88 * that the underlying surface may not be stored in a volatile buffer on all
89 * platforms, and raw access to the surface (using RawAccessRef()) may be much
90 * more expensive than in the InitForDecoder() case.
92 * aBackend specifies the DrawTarget backend type this imgFrame is supposed
93 * to be drawn to.
95 nsresult InitWithDrawable(gfxDrawable* aDrawable, const nsIntSize& aSize,
96 const SurfaceFormat aFormat,
97 SamplingFilter aSamplingFilter,
98 uint32_t aImageFlags, gfx::BackendType aBackend,
99 DrawTarget* aTarget);
101 DrawableFrameRef DrawableRef();
104 * Create a RawAccessFrameRef for the frame.
106 * @param aOnlyFinished If true, only return a valid RawAccessFrameRef if
107 * imgFrame::Finish has been called.
109 RawAccessFrameRef RawAccessRef(bool aOnlyFinished = false);
112 * Make this imgFrame permanently available for raw access.
114 * This is irrevocable, and should be avoided whenever possible, since it
115 * prevents this imgFrame from being optimized and makes it impossible for its
116 * volatile buffer to be freed.
118 * It is an error to call this without already holding a RawAccessFrameRef to
119 * this imgFrame.
121 void SetRawAccessOnly();
123 bool Draw(gfxContext* aContext, const ImageRegion& aRegion,
124 SamplingFilter aSamplingFilter, uint32_t aImageFlags,
125 float aOpacity);
127 nsresult ImageUpdated(const nsIntRect& aUpdateRect);
130 * Mark this imgFrame as completely decoded, and set final options.
132 * You must always call either Finish() or Abort() before releasing the last
133 * RawAccessFrameRef pointing to an imgFrame.
135 * @param aFrameOpacity Whether this imgFrame is opaque.
136 * @param aFinalize Finalize the underlying surface (e.g. so that it
137 * may be marked as read only if possible).
139 void Finish(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
140 bool aFinalize = true);
143 * Mark this imgFrame as aborted. This informs the imgFrame that if it isn't
144 * completely decoded now, it never will be.
146 * You must always call either Finish() or Abort() before releasing the last
147 * RawAccessFrameRef pointing to an imgFrame.
149 void Abort();
152 * Returns true if this imgFrame has been aborted.
154 bool IsAborted() const;
157 * Returns true if this imgFrame is completely decoded.
159 bool IsFinished() const;
162 * Blocks until this imgFrame is either completely decoded, or is marked as
163 * aborted.
165 * Note that calling this on the main thread _blocks the main thread_. Be very
166 * careful in your use of this method to avoid excessive main thread jank or
167 * deadlock.
169 void WaitUntilFinished() const;
172 * Returns the number of bytes per pixel this imgFrame requires. This is a
173 * worst-case value that does not take into account the effects of format
174 * changes caused by Optimize(), since an imgFrame is not optimized throughout
175 * its lifetime.
177 uint32_t GetBytesPerPixel() const { return GetIsPaletted() ? 1 : 4; }
179 const IntSize& GetImageSize() const { return mImageSize; }
180 const IntRect& GetRect() const { return mFrameRect; }
181 IntSize GetSize() const { return mFrameRect.Size(); }
182 const IntRect& GetBlendRect() const { return mBlendRect; }
183 IntRect GetBoundedBlendRect() const {
184 return mBlendRect.Intersect(mFrameRect);
186 FrameTimeout GetTimeout() const { return mTimeout; }
187 BlendMethod GetBlendMethod() const { return mBlendMethod; }
188 DisposalMethod GetDisposalMethod() const { return mDisposalMethod; }
189 bool FormatHasAlpha() const { return mFormat == SurfaceFormat::B8G8R8A8; }
190 void GetImageData(uint8_t** aData, uint32_t* length) const;
191 uint8_t* GetImageData() const;
193 bool GetIsPaletted() const;
194 void GetPaletteData(uint32_t** aPalette, uint32_t* length) const;
195 uint32_t* GetPaletteData() const;
196 uint8_t GetPaletteDepth() const { return mPaletteDepth; }
198 const IntRect& GetDirtyRect() const { return mDirtyRect; }
199 void SetDirtyRect(const IntRect& aDirtyRect) { mDirtyRect = aDirtyRect; }
201 bool IsFullFrame() const { return mIsFullFrame; }
203 bool GetCompositingFailed() const;
204 void SetCompositingFailed(bool val);
206 void SetOptimizable();
208 void FinalizeSurface();
209 already_AddRefed<SourceSurface> GetSourceSurface();
211 struct AddSizeOfCbData {
212 AddSizeOfCbData()
213 : heap(0), nonHeap(0), handles(0), index(0), externalId(0) {}
215 size_t heap;
216 size_t nonHeap;
217 size_t handles;
218 size_t index;
219 uint64_t externalId;
222 typedef std::function<void(AddSizeOfCbData& aMetadata)> AddSizeOfCb;
224 void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
225 const AddSizeOfCb& aCallback) const;
227 private: // methods
228 ~imgFrame();
231 * Used when the caller desires raw access to the underlying frame buffer.
232 * If the locking succeeds, the data pointer to the start of the buffer is
233 * returned, else it returns nullptr.
235 * @param aOnlyFinished If true, only attempt to lock if imgFrame::Finish has
236 * been called.
238 uint8_t* LockImageData(bool aOnlyFinished);
239 nsresult UnlockImageData();
240 nsresult Optimize(gfx::DrawTarget* aTarget);
242 void AssertImageDataLocked() const;
244 bool AreAllPixelsWritten() const;
245 nsresult ImageUpdatedInternal(const nsIntRect& aUpdateRect);
246 void GetImageDataInternal(uint8_t** aData, uint32_t* length) const;
247 uint32_t GetImageBytesPerRow() const;
248 uint32_t GetImageDataLength() const;
249 void FinalizeSurfaceInternal();
252 * @param aTemporary If true, it will assume the caller does not require a
253 * wrapping RecycleSourceSurface to protect the underlying
254 * surface from recycling. The reference to the surface
255 * must be freed before releasing the main thread context.
257 already_AddRefed<SourceSurface> GetSourceSurfaceInternal(bool aTemporary);
259 uint32_t PaletteDataLength() const {
260 return mPaletteDepth ? (size_t(1) << mPaletteDepth) * sizeof(uint32_t) : 0;
263 struct SurfaceWithFormat {
264 RefPtr<gfxDrawable> mDrawable;
265 SurfaceFormat mFormat;
266 SurfaceWithFormat() : mFormat(SurfaceFormat::UNKNOWN) {}
267 SurfaceWithFormat(gfxDrawable* aDrawable, SurfaceFormat aFormat)
268 : mDrawable(aDrawable), mFormat(aFormat) {}
269 SurfaceWithFormat(SurfaceWithFormat&& aOther)
270 : mDrawable(std::move(aOther.mDrawable)), mFormat(aOther.mFormat) {}
271 SurfaceWithFormat& operator=(SurfaceWithFormat&& aOther) {
272 mDrawable = std::move(aOther.mDrawable);
273 mFormat = aOther.mFormat;
274 return *this;
276 SurfaceWithFormat& operator=(const SurfaceWithFormat& aOther) = delete;
277 SurfaceWithFormat(const SurfaceWithFormat& aOther) = delete;
278 bool IsValid() { return !!mDrawable; }
281 SurfaceWithFormat SurfaceForDrawing(bool aDoPartialDecode, bool aDoTile,
282 ImageRegion& aRegion,
283 SourceSurface* aSurface);
285 private: // data
286 friend class DrawableFrameRef;
287 friend class RawAccessFrameRef;
288 friend class RecyclingSourceSurface;
289 friend class UnlockImageDataRunnable;
291 //////////////////////////////////////////////////////////////////////////////
292 // Thread-safe mutable data, protected by mMonitor.
293 //////////////////////////////////////////////////////////////////////////////
295 mutable Monitor mMonitor;
298 * Surface which contains either a weak or a strong reference to its
299 * underlying data buffer. If it is a weak reference, and there are no strong
300 * references, the buffer may be released due to events such as low memory.
302 RefPtr<DataSourceSurface> mRawSurface;
305 * Refers to the same data as mRawSurface, but when set, it guarantees that
306 * we hold a strong reference to the underlying data buffer.
308 RefPtr<DataSourceSurface> mLockedSurface;
311 * Optimized copy of mRawSurface for the DrawTarget that will render it. This
312 * is unused if the DrawTarget is able to render DataSourceSurface buffers
313 * directly.
315 RefPtr<SourceSurface> mOptSurface;
317 nsIntRect mDecoded;
319 //! Number of RawAccessFrameRefs currently alive for this imgFrame.
320 int16_t mLockCount;
322 //! Number of RecyclingSourceSurface's currently alive for this imgFrame.
323 int16_t mRecycleLockCount;
325 bool mAborted;
326 bool mFinished;
327 bool mOptimizable;
328 bool mShouldRecycle;
330 //////////////////////////////////////////////////////////////////////////////
331 // Effectively const data, only mutated in the Init methods.
332 //////////////////////////////////////////////////////////////////////////////
334 //! The size of the buffer we are decoding to.
335 IntSize mImageSize;
337 //! XXX(aosmond): This means something different depending on the context. We
338 //! should correct this.
340 //! There are several different contexts for mFrameRect:
341 //! - If for non-animated image, it will be originate at (0, 0) and matches
342 //! the dimensions of mImageSize.
343 //! - If for an APNG, it also matches the above.
344 //! - If for a GIF which is producing full frames, it matches the above.
345 //! - If for a GIF which is producing partial frames, it matches mBlendRect.
346 IntRect mFrameRect;
348 //! The contents for the frame, as represented in the encoded image. This may
349 //! differ from mImageSize because it may be a partial frame. For the first
350 //! frame, this means we need to shift the data in place, and for animated
351 //! frames, it likely need to combine with a previous frame to get the full
352 //! contents.
353 IntRect mBlendRect;
355 //! This is the region that has changed between this frame and the previous
356 //! frame of an animation. For the first frame, this will be the same as
357 //! mFrameRect.
358 IntRect mDirtyRect;
360 //! The timeout for this frame.
361 FrameTimeout mTimeout;
363 DisposalMethod mDisposalMethod;
364 BlendMethod mBlendMethod;
365 SurfaceFormat mFormat;
367 // The palette and image data for images that are paletted, since Cairo
368 // doesn't support these images.
369 // The paletted data comes first, then the image data itself.
370 // Total length is PaletteDataLength() + GetImageDataLength().
371 uint8_t* mPalettedImageData;
372 uint8_t mPaletteDepth;
374 bool mNonPremult;
376 //! True if the frame has all of the data stored in it, false if it needs to
377 //! be combined with another frame (e.g. the previous frame) to be complete.
378 bool mIsFullFrame;
380 //////////////////////////////////////////////////////////////////////////////
381 // Main-thread-only mutable data.
382 //////////////////////////////////////////////////////////////////////////////
384 bool mCompositingFailed;
388 * A reference to an imgFrame that holds the imgFrame's surface in memory,
389 * allowing drawing. If you have a DrawableFrameRef |ref| and |if (ref)| returns
390 * true, then calls to Draw() and GetSourceSurface() are guaranteed to succeed.
392 class DrawableFrameRef final {
393 typedef gfx::DataSourceSurface DataSourceSurface;
395 public:
396 DrawableFrameRef() {}
398 explicit DrawableFrameRef(imgFrame* aFrame) : mFrame(aFrame) {
399 MOZ_ASSERT(aFrame);
400 MonitorAutoLock lock(aFrame->mMonitor);
401 MOZ_ASSERT(!aFrame->GetIsPaletted(), "Paletted must use RawAccessFrameRef");
403 if (aFrame->mRawSurface) {
404 mRef.emplace(aFrame->mRawSurface, DataSourceSurface::READ);
405 if (!mRef->IsMapped()) {
406 mFrame = nullptr;
407 mRef.reset();
409 } else {
410 MOZ_ASSERT(aFrame->mOptSurface);
414 DrawableFrameRef(DrawableFrameRef&& aOther)
415 : mFrame(aOther.mFrame.forget()), mRef(std::move(aOther.mRef)) {}
417 DrawableFrameRef& operator=(DrawableFrameRef&& aOther) {
418 MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
419 mFrame = aOther.mFrame.forget();
420 mRef = std::move(aOther.mRef);
421 return *this;
424 explicit operator bool() const { return bool(mFrame); }
426 imgFrame* operator->() {
427 MOZ_ASSERT(mFrame);
428 return mFrame;
431 const imgFrame* operator->() const {
432 MOZ_ASSERT(mFrame);
433 return mFrame;
436 imgFrame* get() { return mFrame; }
437 const imgFrame* get() const { return mFrame; }
439 void reset() {
440 mFrame = nullptr;
441 mRef.reset();
444 private:
445 DrawableFrameRef(const DrawableFrameRef& aOther) = delete;
446 DrawableFrameRef& operator=(const DrawableFrameRef& aOther) = delete;
448 RefPtr<imgFrame> mFrame;
449 Maybe<DataSourceSurface::ScopedMap> mRef;
453 * A reference to an imgFrame that holds the imgFrame's surface in memory in a
454 * format appropriate for access as raw data. If you have a RawAccessFrameRef
455 * |ref| and |if (ref)| is true, then calls to GetImageData() and
456 * GetPaletteData() are guaranteed to succeed. This guarantee is stronger than
457 * DrawableFrameRef, so everything that a valid DrawableFrameRef guarantees is
458 * also guaranteed by a valid RawAccessFrameRef.
460 * This may be considerably more expensive than is necessary just for drawing,
461 * so only use this when you need to read or write the raw underlying image data
462 * that the imgFrame holds.
464 * Once all an imgFrame's RawAccessFrameRefs go out of scope, new
465 * RawAccessFrameRefs cannot be created.
467 class RawAccessFrameRef final {
468 public:
469 RawAccessFrameRef() : mData(nullptr) {}
471 explicit RawAccessFrameRef(imgFrame* aFrame, bool aOnlyFinished)
472 : mFrame(aFrame), mData(nullptr) {
473 MOZ_ASSERT(mFrame, "Need a frame");
475 mData = mFrame->LockImageData(aOnlyFinished);
476 if (!mData) {
477 mFrame = nullptr;
481 RawAccessFrameRef(RawAccessFrameRef&& aOther)
482 : mFrame(aOther.mFrame.forget()), mData(aOther.mData) {
483 aOther.mData = nullptr;
486 ~RawAccessFrameRef() {
487 if (mFrame) {
488 mFrame->UnlockImageData();
492 RawAccessFrameRef& operator=(RawAccessFrameRef&& aOther) {
493 MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
495 if (mFrame) {
496 mFrame->UnlockImageData();
499 mFrame = aOther.mFrame.forget();
500 mData = aOther.mData;
501 aOther.mData = nullptr;
503 return *this;
506 explicit operator bool() const { return bool(mFrame); }
508 imgFrame* operator->() {
509 MOZ_ASSERT(mFrame);
510 return mFrame.get();
513 const imgFrame* operator->() const {
514 MOZ_ASSERT(mFrame);
515 return mFrame;
518 imgFrame* get() { return mFrame; }
519 const imgFrame* get() const { return mFrame; }
521 void reset() {
522 if (mFrame) {
523 mFrame->UnlockImageData();
525 mFrame = nullptr;
526 mData = nullptr;
529 uint8_t* Data() const { return mData; }
530 uint32_t PaletteDataLength() const { return mFrame->PaletteDataLength(); }
532 private:
533 RawAccessFrameRef(const RawAccessFrameRef& aOther) = delete;
534 RawAccessFrameRef& operator=(const RawAccessFrameRef& aOther) = delete;
536 RefPtr<imgFrame> mFrame;
537 uint8_t* mData;
540 } // namespace image
541 } // namespace mozilla
543 #endif // mozilla_image_imgFrame_h