Bug 1486801 - Clicking on the [...] should expand the markup container. r=jdescottes
[gecko.git] / image / imgFrame.h
blob1672e7baa84ab57ca1b44d1147adc7344d21edb0
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 {
27 FULLY_OPAQUE,
28 SOME_TRANSPARENCY
31 class imgFrame
33 typedef gfx::Color Color;
34 typedef gfx::DataSourceSurface DataSourceSurface;
35 typedef gfx::DrawTarget DrawTarget;
36 typedef gfx::SamplingFilter SamplingFilter;
37 typedef gfx::IntPoint IntPoint;
38 typedef gfx::IntRect IntRect;
39 typedef gfx::IntSize IntSize;
40 typedef gfx::SourceSurface SourceSurface;
41 typedef gfx::SurfaceFormat SurfaceFormat;
43 public:
44 MOZ_DECLARE_REFCOUNTED_TYPENAME(imgFrame)
45 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(imgFrame)
47 imgFrame();
49 /**
50 * Initialize this imgFrame with an empty surface and prepare it for being
51 * written to by a decoder.
53 * This is appropriate for use with decoded images, but it should not be used
54 * when drawing content into an imgFrame, as it may use a different graphics
55 * backend than normal content drawing.
57 nsresult InitForDecoder(const nsIntSize& aImageSize,
58 const nsIntRect& aRect,
59 SurfaceFormat aFormat,
60 uint8_t aPaletteDepth = 0,
61 bool aNonPremult = false,
62 const Maybe<AnimationParams>& aAnimParams = Nothing());
64 nsresult InitForAnimator(const nsIntSize& aSize,
65 SurfaceFormat aFormat)
67 nsIntRect frameRect(0, 0, aSize.width, aSize.height);
68 AnimationParams animParams { frameRect, FrameTimeout::Forever(),
69 /* aFrameNum */ 1, BlendMethod::OVER,
70 DisposalMethod::NOT_SPECIFIED };
71 return InitForDecoder(aSize, frameRect,
72 aFormat, 0, false, Some(animParams));
76 /**
77 * Initialize this imgFrame with a new surface and draw the provided
78 * gfxDrawable into it.
80 * This is appropriate to use when drawing content into an imgFrame, as it
81 * uses the same graphics backend as normal content drawing. The downside is
82 * that the underlying surface may not be stored in a volatile buffer on all
83 * platforms, and raw access to the surface (using RawAccessRef()) may be much
84 * more expensive than in the InitForDecoder() case.
86 * aBackend specifies the DrawTarget backend type this imgFrame is supposed
87 * to be drawn to.
89 nsresult InitWithDrawable(gfxDrawable* aDrawable,
90 const nsIntSize& aSize,
91 const SurfaceFormat aFormat,
92 SamplingFilter aSamplingFilter,
93 uint32_t aImageFlags,
94 gfx::BackendType aBackend);
96 DrawableFrameRef DrawableRef();
98 /**
99 * Create a RawAccessFrameRef for the frame.
101 * @param aOnlyFinished If true, only return a valid RawAccessFrameRef if
102 * imgFrame::Finish has been called.
104 RawAccessFrameRef RawAccessRef(bool aOnlyFinished = false);
107 * Make this imgFrame permanently available for raw access.
109 * This is irrevocable, and should be avoided whenever possible, since it
110 * prevents this imgFrame from being optimized and makes it impossible for its
111 * volatile buffer to be freed.
113 * It is an error to call this without already holding a RawAccessFrameRef to
114 * this imgFrame.
116 void SetRawAccessOnly();
118 bool Draw(gfxContext* aContext, const ImageRegion& aRegion,
119 SamplingFilter aSamplingFilter, uint32_t aImageFlags,
120 float aOpacity);
122 nsresult ImageUpdated(const nsIntRect& aUpdateRect);
125 * Mark this imgFrame as completely decoded, and set final options.
127 * You must always call either Finish() or Abort() before releasing the last
128 * RawAccessFrameRef pointing to an imgFrame.
130 * @param aFrameOpacity Whether this imgFrame is opaque.
131 * @param aFinalize Finalize the underlying surface (e.g. so that it
132 * may be marked as read only if possible).
134 void Finish(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
135 bool aFinalize = true);
138 * Mark this imgFrame as aborted. This informs the imgFrame that if it isn't
139 * completely decoded now, it never will be.
141 * You must always call either Finish() or Abort() before releasing the last
142 * RawAccessFrameRef pointing to an imgFrame.
144 void Abort();
147 * Returns true if this imgFrame has been aborted.
149 bool IsAborted() const;
152 * Returns true if this imgFrame is completely decoded.
154 bool IsFinished() const;
157 * Blocks until this imgFrame is either completely decoded, or is marked as
158 * aborted.
160 * Note that calling this on the main thread _blocks the main thread_. Be very
161 * careful in your use of this method to avoid excessive main thread jank or
162 * deadlock.
164 void WaitUntilFinished() const;
167 * Returns the number of bytes per pixel this imgFrame requires. This is a
168 * worst-case value that does not take into account the effects of format
169 * changes caused by Optimize(), since an imgFrame is not optimized throughout
170 * its lifetime.
172 uint32_t GetBytesPerPixel() const { return GetIsPaletted() ? 1 : 4; }
174 const IntSize& GetImageSize() const { return mImageSize; }
175 const IntRect& GetRect() const { return mFrameRect; }
176 IntSize GetSize() const { return mFrameRect.Size(); }
177 const IntRect& GetBlendRect() const { return mBlendRect; }
178 IntRect GetBoundedBlendRect() const { return mBlendRect.Intersect(mFrameRect); }
179 FrameTimeout GetTimeout() const { return mTimeout; }
180 BlendMethod GetBlendMethod() const { return mBlendMethod; }
181 DisposalMethod GetDisposalMethod() const { return mDisposalMethod; }
182 bool FormatHasAlpha() const { return mFormat == SurfaceFormat::B8G8R8A8; }
183 void GetImageData(uint8_t** aData, uint32_t* length) const;
184 uint8_t* GetImageData() const;
186 bool GetIsPaletted() const;
187 void GetPaletteData(uint32_t** aPalette, uint32_t* length) const;
188 uint32_t* GetPaletteData() const;
189 uint8_t GetPaletteDepth() const { return mPaletteDepth; }
191 bool GetCompositingFailed() const;
192 void SetCompositingFailed(bool val);
194 void SetOptimizable();
196 void FinalizeSurface();
197 already_AddRefed<SourceSurface> GetSourceSurface();
199 void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut,
200 size_t& aNonHeapSizeOut,
201 size_t& aExtHandlesOut) const;
203 private: // methods
205 ~imgFrame();
208 * Used when the caller desires raw access to the underlying frame buffer.
209 * If the locking succeeds, the data pointer to the start of the buffer is
210 * returned, else it returns nullptr.
212 * @param aOnlyFinished If true, only attempt to lock if imgFrame::Finish has
213 * been called.
215 uint8_t* LockImageData(bool aOnlyFinished);
216 nsresult UnlockImageData();
217 nsresult Optimize(gfx::DrawTarget* aTarget);
219 void AssertImageDataLocked() const;
221 bool AreAllPixelsWritten() const;
222 nsresult ImageUpdatedInternal(const nsIntRect& aUpdateRect);
223 void GetImageDataInternal(uint8_t** aData, uint32_t* length) const;
224 uint32_t GetImageBytesPerRow() const;
225 uint32_t GetImageDataLength() const;
226 void FinalizeSurfaceInternal();
227 already_AddRefed<SourceSurface> GetSourceSurfaceInternal();
229 uint32_t PaletteDataLength() const
231 return mPaletteDepth ? (size_t(1) << mPaletteDepth) * sizeof(uint32_t)
232 : 0;
235 struct SurfaceWithFormat {
236 RefPtr<gfxDrawable> mDrawable;
237 SurfaceFormat mFormat;
238 SurfaceWithFormat()
239 : mFormat(SurfaceFormat::UNKNOWN)
242 SurfaceWithFormat(gfxDrawable* aDrawable, SurfaceFormat aFormat)
243 : mDrawable(aDrawable), mFormat(aFormat)
245 bool IsValid() { return !!mDrawable; }
248 SurfaceWithFormat SurfaceForDrawing(bool aDoPartialDecode,
249 bool aDoTile,
250 ImageRegion& aRegion,
251 SourceSurface* aSurface);
253 private: // data
254 friend class DrawableFrameRef;
255 friend class RawAccessFrameRef;
256 friend class UnlockImageDataRunnable;
258 //////////////////////////////////////////////////////////////////////////////
259 // Thread-safe mutable data, protected by mMonitor.
260 //////////////////////////////////////////////////////////////////////////////
262 mutable Monitor mMonitor;
265 * Surface which contains either a weak or a strong reference to its
266 * underlying data buffer. If it is a weak reference, and there are no strong
267 * references, the buffer may be released due to events such as low memory.
269 RefPtr<DataSourceSurface> mRawSurface;
272 * Refers to the same data as mRawSurface, but when set, it guarantees that
273 * we hold a strong reference to the underlying data buffer.
275 RefPtr<DataSourceSurface> mLockedSurface;
278 * Optimized copy of mRawSurface for the DrawTarget that will render it. This
279 * is unused if the DrawTarget is able to render DataSourceSurface buffers
280 * directly.
282 RefPtr<SourceSurface> mOptSurface;
284 nsIntRect mDecoded;
286 //! Number of RawAccessFrameRefs currently alive for this imgFrame.
287 int32_t mLockCount;
289 bool mAborted;
290 bool mFinished;
291 bool mOptimizable;
294 //////////////////////////////////////////////////////////////////////////////
295 // Effectively const data, only mutated in the Init methods.
296 //////////////////////////////////////////////////////////////////////////////
298 IntSize mImageSize;
299 IntRect mFrameRect;
300 IntRect mBlendRect;
302 //! The timeout for this frame.
303 FrameTimeout mTimeout;
305 DisposalMethod mDisposalMethod;
306 BlendMethod mBlendMethod;
307 SurfaceFormat mFormat;
309 // The palette and image data for images that are paletted, since Cairo
310 // doesn't support these images.
311 // The paletted data comes first, then the image data itself.
312 // Total length is PaletteDataLength() + GetImageDataLength().
313 uint8_t* mPalettedImageData;
314 uint8_t mPaletteDepth;
316 bool mNonPremult;
319 //////////////////////////////////////////////////////////////////////////////
320 // Main-thread-only mutable data.
321 //////////////////////////////////////////////////////////////////////////////
323 bool mCompositingFailed;
327 * A reference to an imgFrame that holds the imgFrame's surface in memory,
328 * allowing drawing. If you have a DrawableFrameRef |ref| and |if (ref)| returns
329 * true, then calls to Draw() and GetSourceSurface() are guaranteed to succeed.
331 class DrawableFrameRef final
333 typedef gfx::DataSourceSurface DataSourceSurface;
335 public:
336 DrawableFrameRef() { }
338 explicit DrawableFrameRef(imgFrame* aFrame)
339 : mFrame(aFrame)
341 MOZ_ASSERT(aFrame);
342 MonitorAutoLock lock(aFrame->mMonitor);
343 MOZ_ASSERT(!aFrame->GetIsPaletted(), "Paletted must use RawAccessFrameRef");
345 if (aFrame->mRawSurface) {
346 mRef.emplace(aFrame->mRawSurface, DataSourceSurface::READ);
347 if (!mRef->IsMapped()) {
348 mFrame = nullptr;
349 mRef.reset();
351 } else {
352 MOZ_ASSERT(aFrame->mOptSurface);
356 DrawableFrameRef(DrawableFrameRef&& aOther)
357 : mFrame(aOther.mFrame.forget())
358 , mRef(std::move(aOther.mRef))
361 DrawableFrameRef& operator=(DrawableFrameRef&& aOther)
363 MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
364 mFrame = aOther.mFrame.forget();
365 mRef = std::move(aOther.mRef);
366 return *this;
369 explicit operator bool() const { return bool(mFrame); }
371 imgFrame* operator->()
373 MOZ_ASSERT(mFrame);
374 return mFrame;
377 const imgFrame* operator->() const
379 MOZ_ASSERT(mFrame);
380 return mFrame;
383 imgFrame* get() { return mFrame; }
384 const imgFrame* get() const { return mFrame; }
386 void reset()
388 mFrame = nullptr;
389 mRef.reset();
392 private:
393 DrawableFrameRef(const DrawableFrameRef& aOther) = delete;
394 DrawableFrameRef& operator=(const DrawableFrameRef& aOther) = delete;
396 RefPtr<imgFrame> mFrame;
397 Maybe<DataSourceSurface::ScopedMap> mRef;
401 * A reference to an imgFrame that holds the imgFrame's surface in memory in a
402 * format appropriate for access as raw data. If you have a RawAccessFrameRef
403 * |ref| and |if (ref)| is true, then calls to GetImageData() and
404 * GetPaletteData() are guaranteed to succeed. This guarantee is stronger than
405 * DrawableFrameRef, so everything that a valid DrawableFrameRef guarantees is
406 * also guaranteed by a valid RawAccessFrameRef.
408 * This may be considerably more expensive than is necessary just for drawing,
409 * so only use this when you need to read or write the raw underlying image data
410 * that the imgFrame holds.
412 * Once all an imgFrame's RawAccessFrameRefs go out of scope, new
413 * RawAccessFrameRefs cannot be created.
415 class RawAccessFrameRef final
417 public:
418 RawAccessFrameRef() : mData(nullptr) { }
420 explicit RawAccessFrameRef(imgFrame* aFrame,
421 bool aOnlyFinished)
422 : mFrame(aFrame)
423 , 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())
435 , mData(aOther.mData)
437 aOther.mData = nullptr;
440 ~RawAccessFrameRef()
442 if (mFrame) {
443 mFrame->UnlockImageData();
447 RawAccessFrameRef& operator=(RawAccessFrameRef&& aOther)
449 MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
451 if (mFrame) {
452 mFrame->UnlockImageData();
455 mFrame = aOther.mFrame.forget();
456 mData = aOther.mData;
457 aOther.mData = nullptr;
459 return *this;
462 explicit operator bool() const { return bool(mFrame); }
464 imgFrame* operator->()
466 MOZ_ASSERT(mFrame);
467 return mFrame.get();
470 const imgFrame* operator->() const
472 MOZ_ASSERT(mFrame);
473 return mFrame;
476 imgFrame* get() { return mFrame; }
477 const imgFrame* get() const { return mFrame; }
479 void reset()
481 if (mFrame) {
482 mFrame->UnlockImageData();
484 mFrame = nullptr;
485 mData = nullptr;
488 uint8_t* Data() const { return mData; }
489 uint32_t PaletteDataLength() const { return mFrame->PaletteDataLength(); }
491 private:
492 RawAccessFrameRef(const RawAccessFrameRef& aOther) = delete;
493 RawAccessFrameRef& operator=(const RawAccessFrameRef& aOther) = delete;
495 RefPtr<imgFrame> mFrame;
496 uint8_t* mData;
499 } // namespace image
500 } // namespace mozilla
502 #endif // mozilla_image_imgFrame_h