Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/image/imgFrame.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
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/. */
6
7
#ifndef mozilla_image_imgFrame_h
8
#define mozilla_image_imgFrame_h
9
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"
18
19
namespace mozilla {
20
namespace image {
21
22
class ImageRegion;
23
class DrawableFrameRef;
24
class RawAccessFrameRef;
25
26
enum class Opacity : uint8_t {
27
  FULLY_OPAQUE,
28
  SOME_TRANSPARENCY
29
};
30
31
class imgFrame
32
{
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;
42
43
public:
44
  MOZ_DECLARE_REFCOUNTED_TYPENAME(imgFrame)
45
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(imgFrame)
46
47
  imgFrame();
48
49
  /**
50
   * Initialize this imgFrame with an empty surface and prepare it for being
51
   * written to by a decoder.
52
   *
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.
56
   */
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(),
63
                          bool aIsFullFrame = false);
64
65
  nsresult InitForAnimator(const nsIntSize& aSize,
66
                           SurfaceFormat aFormat)
67
0
  {
68
0
    nsIntRect frameRect(0, 0, aSize.width, aSize.height);
69
0
    AnimationParams animParams { frameRect, FrameTimeout::Forever(),
70
0
                                 /* aFrameNum */ 1, BlendMethod::OVER,
71
0
                                 DisposalMethod::NOT_SPECIFIED };
72
0
    // We set aIsFullFrame to false because we don't want the compositing frame
73
0
    // to be allocated into shared memory for WebRender. mIsFullFrame is only
74
0
    // otherwise used for frames produced by Decoder, so it isn't relevant.
75
0
    return InitForDecoder(aSize, frameRect, aFormat, /* aPaletteDepth */ 0,
76
0
                          /* aNonPremult */ false, Some(animParams),
77
0
                          /* aIsFullFrame */ false);
78
0
  }
79
80
81
  /**
82
   * Initialize this imgFrame with a new surface and draw the provided
83
   * gfxDrawable into it.
84
   *
85
   * This is appropriate to use when drawing content into an imgFrame, as it
86
   * uses the same graphics backend as normal content drawing. The downside is
87
   * that the underlying surface may not be stored in a volatile buffer on all
88
   * platforms, and raw access to the surface (using RawAccessRef()) may be much
89
   * more expensive than in the InitForDecoder() case.
90
   *
91
   * aBackend specifies the DrawTarget backend type this imgFrame is supposed
92
   *          to be drawn to.
93
   */
94
  nsresult InitWithDrawable(gfxDrawable* aDrawable,
95
                            const nsIntSize& aSize,
96
                            const SurfaceFormat aFormat,
97
                            SamplingFilter aSamplingFilter,
98
                            uint32_t aImageFlags,
99
                            gfx::BackendType aBackend);
100
101
  DrawableFrameRef DrawableRef();
102
103
  /**
104
   * Create a RawAccessFrameRef for the frame.
105
   *
106
   * @param aOnlyFinished If true, only return a valid RawAccessFrameRef if
107
   *                      imgFrame::Finish has been called.
108
   */
109
  RawAccessFrameRef RawAccessRef(bool aOnlyFinished = false);
110
111
  /**
112
   * Make this imgFrame permanently available for raw access.
113
   *
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.
117
   *
118
   * It is an error to call this without already holding a RawAccessFrameRef to
119
   * this imgFrame.
120
   */
121
  void SetRawAccessOnly();
122
123
  bool Draw(gfxContext* aContext, const ImageRegion& aRegion,
124
            SamplingFilter aSamplingFilter, uint32_t aImageFlags,
125
            float aOpacity);
126
127
  nsresult ImageUpdated(const nsIntRect& aUpdateRect);
128
129
  /**
130
   * Mark this imgFrame as completely decoded, and set final options.
131
   *
132
   * You must always call either Finish() or Abort() before releasing the last
133
   * RawAccessFrameRef pointing to an imgFrame.
134
   *
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).
138
   */
139
  void Finish(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
140
              bool aFinalize = true);
141
142
  /**
143
   * Mark this imgFrame as aborted. This informs the imgFrame that if it isn't
144
   * completely decoded now, it never will be.
145
   *
146
   * You must always call either Finish() or Abort() before releasing the last
147
   * RawAccessFrameRef pointing to an imgFrame.
148
   */
149
  void Abort();
150
151
  /**
152
   * Returns true if this imgFrame has been aborted.
153
   */
154
  bool IsAborted() const;
155
156
  /**
157
   * Returns true if this imgFrame is completely decoded.
158
   */
159
  bool IsFinished() const;
160
161
  /**
162
   * Blocks until this imgFrame is either completely decoded, or is marked as
163
   * aborted.
164
   *
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.
168
   */
169
  void WaitUntilFinished() const;
170
171
  /**
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.
176
   */
177
0
  uint32_t GetBytesPerPixel() const { return GetIsPaletted() ? 1 : 4; }
178
179
0
  const IntSize& GetImageSize() const { return mImageSize; }
180
0
  const IntRect& GetRect() const { return mFrameRect; }
181
0
  IntSize GetSize() const { return mFrameRect.Size(); }
182
0
  const IntRect& GetBlendRect() const { return mBlendRect; }
183
0
  IntRect GetBoundedBlendRect() const { return mBlendRect.Intersect(mFrameRect); }
184
0
  FrameTimeout GetTimeout() const { return mTimeout; }
185
0
  BlendMethod GetBlendMethod() const { return mBlendMethod; }
186
0
  DisposalMethod GetDisposalMethod() const { return mDisposalMethod; }
187
0
  bool FormatHasAlpha() const { return mFormat == SurfaceFormat::B8G8R8A8; }
188
  void GetImageData(uint8_t** aData, uint32_t* length) const;
189
  uint8_t* GetImageData() const;
190
191
  bool GetIsPaletted() const;
192
  void GetPaletteData(uint32_t** aPalette, uint32_t* length) const;
193
  uint32_t* GetPaletteData() const;
194
0
  uint8_t GetPaletteDepth() const { return mPaletteDepth; }
195
196
0
  const IntRect& GetDirtyRect() const { return mDirtyRect; }
197
0
  void SetDirtyRect(const IntRect& aDirtyRect) { mDirtyRect = aDirtyRect; }
198
199
0
  bool IsFullFrame() const { return mIsFullFrame; }
200
201
  bool GetCompositingFailed() const;
202
  void SetCompositingFailed(bool val);
203
204
  void SetOptimizable();
205
206
  void FinalizeSurface();
207
  already_AddRefed<SourceSurface> GetSourceSurface();
208
209
  void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut,
210
                              size_t& aNonHeapSizeOut,
211
                              size_t& aExtHandlesOut) const;
212
213
private: // methods
214
215
  ~imgFrame();
216
217
  /**
218
   * Used when the caller desires raw access to the underlying frame buffer.
219
   * If the locking succeeds, the data pointer to the start of the buffer is
220
   * returned, else it returns nullptr.
221
   *
222
   * @param aOnlyFinished If true, only attempt to lock if imgFrame::Finish has
223
   *                      been called.
224
   */
225
  uint8_t* LockImageData(bool aOnlyFinished);
226
  nsresult UnlockImageData();
227
  nsresult Optimize(gfx::DrawTarget* aTarget);
228
229
  void AssertImageDataLocked() const;
230
231
  bool AreAllPixelsWritten() const;
232
  nsresult ImageUpdatedInternal(const nsIntRect& aUpdateRect);
233
  void GetImageDataInternal(uint8_t** aData, uint32_t* length) const;
234
  uint32_t GetImageBytesPerRow() const;
235
  uint32_t GetImageDataLength() const;
236
  void FinalizeSurfaceInternal();
237
  already_AddRefed<SourceSurface> GetSourceSurfaceInternal();
238
239
  uint32_t PaletteDataLength() const
240
0
  {
241
0
    return mPaletteDepth ? (size_t(1) << mPaletteDepth) * sizeof(uint32_t)
242
0
                         : 0;
243
0
  }
244
245
  struct SurfaceWithFormat {
246
    RefPtr<gfxDrawable> mDrawable;
247
    SurfaceFormat mFormat;
248
    SurfaceWithFormat()
249
      : mFormat(SurfaceFormat::UNKNOWN)
250
0
    {
251
0
    }
252
    SurfaceWithFormat(gfxDrawable* aDrawable, SurfaceFormat aFormat)
253
      : mDrawable(aDrawable), mFormat(aFormat)
254
0
    { }
255
0
    bool IsValid() { return !!mDrawable; }
256
  };
257
258
  SurfaceWithFormat SurfaceForDrawing(bool               aDoPartialDecode,
259
                                      bool               aDoTile,
260
                                      ImageRegion&       aRegion,
261
                                      SourceSurface*     aSurface);
262
263
private: // data
264
  friend class DrawableFrameRef;
265
  friend class RawAccessFrameRef;
266
  friend class UnlockImageDataRunnable;
267
268
  //////////////////////////////////////////////////////////////////////////////
269
  // Thread-safe mutable data, protected by mMonitor.
270
  //////////////////////////////////////////////////////////////////////////////
271
272
  mutable Monitor mMonitor;
273
274
  /**
275
   * Surface which contains either a weak or a strong reference to its
276
   * underlying data buffer. If it is a weak reference, and there are no strong
277
   * references, the buffer may be released due to events such as low memory.
278
   */
279
  RefPtr<DataSourceSurface> mRawSurface;
280
281
  /**
282
   * Refers to the same data as mRawSurface, but when set, it guarantees that
283
   * we hold a strong reference to the underlying data buffer.
284
   */
285
  RefPtr<DataSourceSurface> mLockedSurface;
286
287
  /**
288
   * Optimized copy of mRawSurface for the DrawTarget that will render it. This
289
   * is unused if the DrawTarget is able to render DataSourceSurface buffers
290
   * directly.
291
   */
292
  RefPtr<SourceSurface> mOptSurface;
293
294
  nsIntRect mDecoded;
295
296
  //! Number of RawAccessFrameRefs currently alive for this imgFrame.
297
  int32_t mLockCount;
298
299
  bool mAborted;
300
  bool mFinished;
301
  bool mOptimizable;
302
303
304
  //////////////////////////////////////////////////////////////////////////////
305
  // Effectively const data, only mutated in the Init methods.
306
  //////////////////////////////////////////////////////////////////////////////
307
308
  //! The size of the buffer we are decoding to.
309
  IntSize      mImageSize;
310
311
  //! XXX(aosmond): This means something different depending on the context. We
312
  //!               should correct this.
313
  //!
314
  //! There are several different contexts for mFrameRect:
315
  //! - If for non-animated image, it will be originate at (0, 0) and matches
316
  //!   the dimensions of mImageSize.
317
  //! - If for an APNG, it also matches the above.
318
  //! - If for a GIF which is producing full frames, it matches the above.
319
  //! - If for a GIF which is producing partial frames, it matches mBlendRect.
320
  IntRect      mFrameRect;
321
322
  //! The contents for the frame, as represented in the encoded image. This may
323
  //! differ from mImageSize because it may be a partial frame. For the first
324
  //! frame, this means we need to shift the data in place, and for animated
325
  //! frames, it likely need to combine with a previous frame to get the full
326
  //! contents.
327
  IntRect      mBlendRect;
328
329
  //! This is the region that has changed between this frame and the previous
330
  //! frame of an animation. For the first frame, this will be the same as
331
  //! mFrameRect.
332
  IntRect      mDirtyRect;
333
334
  //! The timeout for this frame.
335
  FrameTimeout mTimeout;
336
337
  DisposalMethod mDisposalMethod;
338
  BlendMethod    mBlendMethod;
339
  SurfaceFormat  mFormat;
340
341
  // The palette and image data for images that are paletted, since Cairo
342
  // doesn't support these images.
343
  // The paletted data comes first, then the image data itself.
344
  // Total length is PaletteDataLength() + GetImageDataLength().
345
  uint8_t*     mPalettedImageData;
346
  uint8_t      mPaletteDepth;
347
348
  bool mNonPremult;
349
350
  //! True if the frame has all of the data stored in it, false if it needs to
351
  //! be combined with another frame (e.g. the previous frame) to be complete.
352
  bool mIsFullFrame;
353
354
  //////////////////////////////////////////////////////////////////////////////
355
  // Main-thread-only mutable data.
356
  //////////////////////////////////////////////////////////////////////////////
357
358
  bool mCompositingFailed;
359
};
360
361
/**
362
 * A reference to an imgFrame that holds the imgFrame's surface in memory,
363
 * allowing drawing. If you have a DrawableFrameRef |ref| and |if (ref)| returns
364
 * true, then calls to Draw() and GetSourceSurface() are guaranteed to succeed.
365
 */
366
class DrawableFrameRef final
367
{
368
  typedef gfx::DataSourceSurface DataSourceSurface;
369
370
public:
371
0
  DrawableFrameRef() { }
372
373
  explicit DrawableFrameRef(imgFrame* aFrame)
374
    : mFrame(aFrame)
375
0
  {
376
0
    MOZ_ASSERT(aFrame);
377
0
    MonitorAutoLock lock(aFrame->mMonitor);
378
0
    MOZ_ASSERT(!aFrame->GetIsPaletted(), "Paletted must use RawAccessFrameRef");
379
0
380
0
    if (aFrame->mRawSurface) {
381
0
      mRef.emplace(aFrame->mRawSurface, DataSourceSurface::READ);
382
0
      if (!mRef->IsMapped()) {
383
0
        mFrame = nullptr;
384
0
        mRef.reset();
385
0
      }
386
0
    } else {
387
0
      MOZ_ASSERT(aFrame->mOptSurface);
388
0
    }
389
0
  }
390
391
  DrawableFrameRef(DrawableFrameRef&& aOther)
392
    : mFrame(aOther.mFrame.forget())
393
    , mRef(std::move(aOther.mRef))
394
0
  { }
395
396
  DrawableFrameRef& operator=(DrawableFrameRef&& aOther)
397
0
  {
398
0
    MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
399
0
    mFrame = aOther.mFrame.forget();
400
0
    mRef = std::move(aOther.mRef);
401
0
    return *this;
402
0
  }
403
404
0
  explicit operator bool() const { return bool(mFrame); }
405
406
  imgFrame* operator->()
407
0
  {
408
0
    MOZ_ASSERT(mFrame);
409
0
    return mFrame;
410
0
  }
411
412
  const imgFrame* operator->() const
413
0
  {
414
0
    MOZ_ASSERT(mFrame);
415
0
    return mFrame;
416
0
  }
417
418
0
  imgFrame* get() { return mFrame; }
419
0
  const imgFrame* get() const { return mFrame; }
420
421
  void reset()
422
0
  {
423
0
    mFrame = nullptr;
424
0
    mRef.reset();
425
0
  }
426
427
private:
428
  DrawableFrameRef(const DrawableFrameRef& aOther) = delete;
429
  DrawableFrameRef& operator=(const DrawableFrameRef& aOther) = delete;
430
431
  RefPtr<imgFrame> mFrame;
432
  Maybe<DataSourceSurface::ScopedMap> mRef;
433
};
434
435
/**
436
 * A reference to an imgFrame that holds the imgFrame's surface in memory in a
437
 * format appropriate for access as raw data. If you have a RawAccessFrameRef
438
 * |ref| and |if (ref)| is true, then calls to GetImageData() and
439
 * GetPaletteData() are guaranteed to succeed. This guarantee is stronger than
440
 * DrawableFrameRef, so everything that a valid DrawableFrameRef guarantees is
441
 * also guaranteed by a valid RawAccessFrameRef.
442
 *
443
 * This may be considerably more expensive than is necessary just for drawing,
444
 * so only use this when you need to read or write the raw underlying image data
445
 * that the imgFrame holds.
446
 *
447
 * Once all an imgFrame's RawAccessFrameRefs go out of scope, new
448
 * RawAccessFrameRefs cannot be created.
449
 */
450
class RawAccessFrameRef final
451
{
452
public:
453
0
  RawAccessFrameRef() : mData(nullptr) { }
454
455
  explicit RawAccessFrameRef(imgFrame* aFrame,
456
                             bool aOnlyFinished)
457
    : mFrame(aFrame)
458
    , mData(nullptr)
459
0
  {
460
0
    MOZ_ASSERT(mFrame, "Need a frame");
461
0
462
0
    mData = mFrame->LockImageData(aOnlyFinished);
463
0
    if (!mData) {
464
0
      mFrame = nullptr;
465
0
    }
466
0
  }
467
468
  RawAccessFrameRef(RawAccessFrameRef&& aOther)
469
    : mFrame(aOther.mFrame.forget())
470
    , mData(aOther.mData)
471
0
  {
472
0
    aOther.mData = nullptr;
473
0
  }
474
475
  ~RawAccessFrameRef()
476
0
  {
477
0
    if (mFrame) {
478
0
      mFrame->UnlockImageData();
479
0
    }
480
0
  }
481
482
  RawAccessFrameRef& operator=(RawAccessFrameRef&& aOther)
483
0
  {
484
0
    MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
485
0
486
0
    if (mFrame) {
487
0
      mFrame->UnlockImageData();
488
0
    }
489
0
490
0
    mFrame = aOther.mFrame.forget();
491
0
    mData = aOther.mData;
492
0
    aOther.mData = nullptr;
493
0
494
0
    return *this;
495
0
  }
496
497
0
  explicit operator bool() const { return bool(mFrame); }
498
499
  imgFrame* operator->()
500
0
  {
501
0
    MOZ_ASSERT(mFrame);
502
0
    return mFrame.get();
503
0
  }
504
505
  const imgFrame* operator->() const
506
0
  {
507
0
    MOZ_ASSERT(mFrame);
508
0
    return mFrame;
509
0
  }
510
511
0
  imgFrame* get() { return mFrame; }
512
0
  const imgFrame* get() const { return mFrame; }
513
514
  void reset()
515
0
  {
516
0
    if (mFrame) {
517
0
      mFrame->UnlockImageData();
518
0
    }
519
0
    mFrame = nullptr;
520
0
    mData = nullptr;
521
0
  }
522
523
0
  uint8_t* Data() const { return mData; }
524
0
  uint32_t PaletteDataLength() const { return mFrame->PaletteDataLength(); }
525
526
private:
527
  RawAccessFrameRef(const RawAccessFrameRef& aOther) = delete;
528
  RawAccessFrameRef& operator=(const RawAccessFrameRef& aOther) = delete;
529
530
  RefPtr<imgFrame> mFrame;
531
  uint8_t* mData;
532
};
533
534
} // namespace image
535
} // namespace mozilla
536
537
#endif // mozilla_image_imgFrame_h