Bug 1726781 [wpt PR 30110] - Fix column spanner inline-size:auto issues., a=testonly
[gecko.git] / image / imgFrame.h
blob48e1847d81944a82bd022095c90f195180ce67e4
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/Maybe.h"
17 #include "mozilla/MemoryReporting.h"
18 #include "mozilla/Monitor.h"
19 #include "nsRect.h"
21 namespace mozilla {
22 namespace image {
24 class ImageRegion;
25 class DrawableFrameRef;
26 class RawAccessFrameRef;
28 enum class Opacity : uint8_t { FULLY_OPAQUE, SOME_TRANSPARENCY };
30 class imgFrame {
31 typedef gfx::DataSourceSurface DataSourceSurface;
32 typedef gfx::DrawTarget DrawTarget;
33 typedef gfx::SamplingFilter SamplingFilter;
34 typedef gfx::IntPoint IntPoint;
35 typedef gfx::IntRect IntRect;
36 typedef gfx::IntSize IntSize;
37 typedef gfx::SourceSurface SourceSurface;
38 typedef gfx::SurfaceFormat SurfaceFormat;
40 public:
41 MOZ_DECLARE_REFCOUNTED_TYPENAME(imgFrame)
42 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(imgFrame)
44 imgFrame();
46 /**
47 * Initialize this imgFrame with an empty surface and prepare it for being
48 * written to by a decoder.
50 * This is appropriate for use with decoded images, but it should not be used
51 * when drawing content into an imgFrame, as it may use a different graphics
52 * backend than normal content drawing.
54 nsresult InitForDecoder(const nsIntSize& aImageSize, SurfaceFormat aFormat,
55 bool aNonPremult,
56 const Maybe<AnimationParams>& aAnimParams,
57 bool aShouldRecycle);
59 /**
60 * Reinitialize this imgFrame with the new parameters, but otherwise retain
61 * the underlying buffer.
63 * This is appropriate for use with animated images, where the decoder was
64 * given an IDecoderFrameRecycler object which may yield a recycled imgFrame
65 * that was discarded to save memory.
67 nsresult InitForDecoderRecycle(const AnimationParams& aAnimParams);
69 /**
70 * Initialize this imgFrame with a new surface and draw the provided
71 * gfxDrawable into it.
73 * This is appropriate to use when drawing content into an imgFrame, as it
74 * uses the same graphics backend as normal content drawing. The downside is
75 * that the underlying surface may not be stored in a volatile buffer on all
76 * platforms, and raw access to the surface (using RawAccessRef()) may be much
77 * more expensive than in the InitForDecoder() case.
79 * aBackend specifies the DrawTarget backend type this imgFrame is supposed
80 * to be drawn to.
82 nsresult InitWithDrawable(gfxDrawable* aDrawable, const nsIntSize& aSize,
83 const SurfaceFormat aFormat,
84 SamplingFilter aSamplingFilter,
85 uint32_t aImageFlags, gfx::BackendType aBackend);
87 DrawableFrameRef DrawableRef();
89 /**
90 * Create a RawAccessFrameRef for the frame.
92 * @param aOnlyFinished If true, only return a valid RawAccessFrameRef if
93 * imgFrame::Finish has been called.
95 RawAccessFrameRef RawAccessRef(bool aOnlyFinished = false);
97 /**
98 * Make this imgFrame permanently available for raw access.
100 * This is irrevocable, and should be avoided whenever possible, since it
101 * prevents this imgFrame from being optimized and makes it impossible for its
102 * volatile buffer to be freed.
104 * It is an error to call this without already holding a RawAccessFrameRef to
105 * this imgFrame.
107 void SetRawAccessOnly();
109 bool Draw(gfxContext* aContext, const ImageRegion& aRegion,
110 SamplingFilter aSamplingFilter, uint32_t aImageFlags,
111 float aOpacity);
113 nsresult ImageUpdated(const nsIntRect& aUpdateRect);
116 * Mark this imgFrame as completely decoded, and set final options.
118 * You must always call either Finish() or Abort() before releasing the last
119 * RawAccessFrameRef pointing to an imgFrame.
121 * @param aFrameOpacity Whether this imgFrame is opaque.
122 * @param aFinalize Finalize the underlying surface (e.g. so that it
123 * may be marked as read only if possible).
125 void Finish(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
126 bool aFinalize = true);
129 * Mark this imgFrame as aborted. This informs the imgFrame that if it isn't
130 * completely decoded now, it never will be.
132 * You must always call either Finish() or Abort() before releasing the last
133 * RawAccessFrameRef pointing to an imgFrame.
135 void Abort();
138 * Returns true if this imgFrame has been aborted.
140 bool IsAborted() const;
143 * Returns true if this imgFrame is completely decoded.
145 bool IsFinished() const;
148 * Blocks until this imgFrame is either completely decoded, or is marked as
149 * aborted.
151 * Note that calling this on the main thread _blocks the main thread_. Be very
152 * careful in your use of this method to avoid excessive main thread jank or
153 * deadlock.
155 void WaitUntilFinished() const;
158 * Returns the number of bytes per pixel this imgFrame requires. This is a
159 * worst-case value that does not take into account the effects of format
160 * changes caused by Optimize(), since an imgFrame is not optimized throughout
161 * its lifetime.
163 uint32_t GetBytesPerPixel() const { return 4; }
165 const IntSize& GetSize() const { return mImageSize; }
166 IntRect GetRect() const { return IntRect(IntPoint(0, 0), mImageSize); }
167 const IntRect& GetBlendRect() const { return mBlendRect; }
168 IntRect GetBoundedBlendRect() const {
169 return mBlendRect.Intersect(GetRect());
171 FrameTimeout GetTimeout() const { return mTimeout; }
172 BlendMethod GetBlendMethod() const { return mBlendMethod; }
173 DisposalMethod GetDisposalMethod() const { return mDisposalMethod; }
174 bool FormatHasAlpha() const { return mFormat == SurfaceFormat::OS_RGBA; }
175 void GetImageData(uint8_t** aData, uint32_t* length) const;
176 uint8_t* GetImageData() const;
178 const IntRect& GetDirtyRect() const { return mDirtyRect; }
179 void SetDirtyRect(const IntRect& aDirtyRect) { mDirtyRect = aDirtyRect; }
181 void SetOptimizable();
183 void FinalizeSurface();
184 already_AddRefed<SourceSurface> GetSourceSurface();
186 struct AddSizeOfCbData : public SourceSurface::SizeOfInfo {
187 AddSizeOfCbData()
188 : SourceSurface::SizeOfInfo(), mIndex(0), mFinished(false) {}
190 const gfx::SourceSurface* mSurface;
191 size_t mIndex;
192 bool mFinished;
195 typedef std::function<void(AddSizeOfCbData& aMetadata)> AddSizeOfCb;
197 void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
198 const AddSizeOfCb& aCallback) const;
200 private: // methods
201 ~imgFrame();
204 * Used when the caller desires raw access to the underlying frame buffer.
205 * If the locking succeeds, the data pointer to the start of the buffer is
206 * returned, else it returns nullptr.
208 * @param aOnlyFinished If true, only attempt to lock if imgFrame::Finish has
209 * been called.
211 uint8_t* LockImageData(bool aOnlyFinished);
212 nsresult UnlockImageData();
213 nsresult Optimize(gfx::DrawTarget* aTarget);
215 void AssertImageDataLocked() const;
217 bool AreAllPixelsWritten() const;
218 nsresult ImageUpdatedInternal(const nsIntRect& aUpdateRect);
219 void GetImageDataInternal(uint8_t** aData, uint32_t* length) const;
220 uint32_t GetImageBytesPerRow() const;
221 uint32_t GetImageDataLength() const;
222 void FinalizeSurfaceInternal();
223 already_AddRefed<SourceSurface> GetSourceSurfaceInternal();
225 struct SurfaceWithFormat {
226 RefPtr<gfxDrawable> mDrawable;
227 SurfaceFormat mFormat;
228 SurfaceWithFormat() : mFormat(SurfaceFormat::UNKNOWN) {}
229 SurfaceWithFormat(gfxDrawable* aDrawable, SurfaceFormat aFormat)
230 : mDrawable(aDrawable), mFormat(aFormat) {}
231 SurfaceWithFormat(SurfaceWithFormat&& aOther)
232 : mDrawable(std::move(aOther.mDrawable)), mFormat(aOther.mFormat) {}
233 SurfaceWithFormat& operator=(SurfaceWithFormat&& aOther) {
234 mDrawable = std::move(aOther.mDrawable);
235 mFormat = aOther.mFormat;
236 return *this;
238 SurfaceWithFormat& operator=(const SurfaceWithFormat& aOther) = delete;
239 SurfaceWithFormat(const SurfaceWithFormat& aOther) = delete;
240 bool IsValid() { return !!mDrawable; }
243 SurfaceWithFormat SurfaceForDrawing(bool aDoPartialDecode, bool aDoTile,
244 ImageRegion& aRegion,
245 SourceSurface* aSurface);
247 private: // data
248 friend class DrawableFrameRef;
249 friend class RawAccessFrameRef;
250 friend class UnlockImageDataRunnable;
252 //////////////////////////////////////////////////////////////////////////////
253 // Thread-safe mutable data, protected by mMonitor.
254 //////////////////////////////////////////////////////////////////////////////
256 mutable Monitor mMonitor;
259 * Surface which contains either a weak or a strong reference to its
260 * underlying data buffer. If it is a weak reference, and there are no strong
261 * references, the buffer may be released due to events such as low memory.
263 RefPtr<DataSourceSurface> mRawSurface;
264 RefPtr<DataSourceSurface> mBlankRawSurface;
267 * Refers to the same data as mRawSurface, but when set, it guarantees that
268 * we hold a strong reference to the underlying data buffer.
270 RefPtr<DataSourceSurface> mLockedSurface;
271 RefPtr<DataSourceSurface> mBlankLockedSurface;
274 * Optimized copy of mRawSurface for the DrawTarget that will render it. This
275 * is unused if the DrawTarget is able to render DataSourceSurface buffers
276 * directly.
278 RefPtr<SourceSurface> mOptSurface;
280 nsIntRect mDecoded;
282 //! Number of RawAccessFrameRefs currently alive for this imgFrame.
283 int16_t mLockCount;
285 bool mAborted;
286 bool mFinished;
287 bool mOptimizable;
288 bool mShouldRecycle;
290 //////////////////////////////////////////////////////////////////////////////
291 // Effectively const data, only mutated in the Init methods.
292 //////////////////////////////////////////////////////////////////////////////
294 //! The size of the buffer we are decoding to.
295 IntSize mImageSize;
297 //! The contents for the frame, as represented in the encoded image. This may
298 //! differ from mImageSize because it may be a partial frame. For the first
299 //! frame, this means we need to shift the data in place, and for animated
300 //! frames, it likely need to combine with a previous frame to get the full
301 //! contents.
302 IntRect mBlendRect;
304 //! This is the region that has changed between this frame and the previous
305 //! frame of an animation. For the first frame, this will be the same as
306 //! mFrameRect.
307 IntRect mDirtyRect;
309 //! The timeout for this frame.
310 FrameTimeout mTimeout;
312 DisposalMethod mDisposalMethod;
313 BlendMethod mBlendMethod;
314 SurfaceFormat mFormat;
316 bool mNonPremult;
320 * A reference to an imgFrame that holds the imgFrame's surface in memory,
321 * allowing drawing. If you have a DrawableFrameRef |ref| and |if (ref)| returns
322 * true, then calls to Draw() and GetSourceSurface() are guaranteed to succeed.
324 class DrawableFrameRef final {
325 typedef gfx::DataSourceSurface DataSourceSurface;
327 public:
328 DrawableFrameRef() {}
330 explicit DrawableFrameRef(imgFrame* aFrame) : mFrame(aFrame) {
331 MOZ_ASSERT(aFrame);
332 MonitorAutoLock lock(aFrame->mMonitor);
334 if (aFrame->mRawSurface) {
335 mRef.emplace(aFrame->mRawSurface, DataSourceSurface::READ);
336 if (!mRef->IsMapped()) {
337 mFrame = nullptr;
338 mRef.reset();
340 } else if (!aFrame->mOptSurface || !aFrame->mOptSurface->IsValid()) {
341 // The optimized surface has become invalid, so we need to redecode.
342 // For example, on Windows, there may have been a device reset, and
343 // all D2D surfaces now need to be recreated.
344 mFrame = nullptr;
348 DrawableFrameRef(DrawableFrameRef&& aOther)
349 : mFrame(std::move(aOther.mFrame)), mRef(std::move(aOther.mRef)) {}
351 DrawableFrameRef& operator=(DrawableFrameRef&& aOther) {
352 MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
353 mFrame = std::move(aOther.mFrame);
354 mRef = std::move(aOther.mRef);
355 return *this;
358 explicit operator bool() const { return bool(mFrame); }
360 imgFrame* operator->() {
361 MOZ_ASSERT(mFrame);
362 return mFrame;
365 const imgFrame* operator->() const {
366 MOZ_ASSERT(mFrame);
367 return mFrame;
370 imgFrame* get() { return mFrame; }
371 const imgFrame* get() const { return mFrame; }
373 void reset() {
374 mFrame = nullptr;
375 mRef.reset();
378 private:
379 DrawableFrameRef(const DrawableFrameRef& aOther) = delete;
380 DrawableFrameRef& operator=(const DrawableFrameRef& aOther) = delete;
382 RefPtr<imgFrame> mFrame;
383 Maybe<DataSourceSurface::ScopedMap> mRef;
387 * A reference to an imgFrame that holds the imgFrame's surface in memory in a
388 * format appropriate for access as raw data. If you have a RawAccessFrameRef
389 * |ref| and |if (ref)| is true, then calls to GetImageData() is guaranteed to
390 * succeed. This guarantee is stronger than DrawableFrameRef, so everything that
391 * a valid DrawableFrameRef guarantees is also guaranteed by a valid
392 * RawAccessFrameRef.
394 * This may be considerably more expensive than is necessary just for drawing,
395 * so only use this when you need to read or write the raw underlying image data
396 * that the imgFrame holds.
398 * Once all an imgFrame's RawAccessFrameRefs go out of scope, new
399 * RawAccessFrameRefs cannot be created.
401 class RawAccessFrameRef final {
402 public:
403 RawAccessFrameRef() : mData(nullptr) {}
405 explicit RawAccessFrameRef(imgFrame* aFrame, bool aOnlyFinished)
406 : mFrame(aFrame), mData(nullptr) {
407 MOZ_ASSERT(mFrame, "Need a frame");
409 mData = mFrame->LockImageData(aOnlyFinished);
410 if (!mData) {
411 mFrame = nullptr;
415 RawAccessFrameRef(RawAccessFrameRef&& aOther)
416 : mFrame(std::move(aOther.mFrame)), mData(aOther.mData) {
417 aOther.mData = nullptr;
420 ~RawAccessFrameRef() {
421 if (mFrame) {
422 mFrame->UnlockImageData();
426 RawAccessFrameRef& operator=(RawAccessFrameRef&& aOther) {
427 MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
429 if (mFrame) {
430 mFrame->UnlockImageData();
433 mFrame = std::move(aOther.mFrame);
434 mData = aOther.mData;
435 aOther.mData = nullptr;
437 return *this;
440 explicit operator bool() const { return bool(mFrame); }
442 imgFrame* operator->() {
443 MOZ_ASSERT(mFrame);
444 return mFrame.get();
447 const imgFrame* operator->() const {
448 MOZ_ASSERT(mFrame);
449 return mFrame;
452 imgFrame* get() { return mFrame; }
453 const imgFrame* get() const { return mFrame; }
455 void reset() {
456 if (mFrame) {
457 mFrame->UnlockImageData();
459 mFrame = nullptr;
460 mData = nullptr;
463 uint8_t* Data() const { return mData; }
465 private:
466 RawAccessFrameRef(const RawAccessFrameRef& aOther) = delete;
467 RawAccessFrameRef& operator=(const RawAccessFrameRef& aOther) = delete;
469 RefPtr<imgFrame> mFrame;
470 uint8_t* mData;
473 } // namespace image
474 } // namespace mozilla
476 #endif // mozilla_image_imgFrame_h