Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/image/Image.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#ifndef mozilla_image_Image_h
7
#define mozilla_image_Image_h
8
9
#include "mozilla/MemoryReporting.h"
10
#include "mozilla/Tuple.h"
11
#include "mozilla/TimeStamp.h"
12
#include "gfx2DGlue.h"
13
#include "imgIContainer.h"
14
#include "ImageContainer.h"
15
#include "LookupResult.h"
16
#include "nsStringFwd.h"
17
#include "ProgressTracker.h"
18
#include "SurfaceCache.h"
19
20
class nsIRequest;
21
class nsIInputStream;
22
23
namespace mozilla {
24
namespace image {
25
26
class Image;
27
28
///////////////////////////////////////////////////////////////////////////////
29
// Memory Reporting
30
///////////////////////////////////////////////////////////////////////////////
31
32
struct MemoryCounter
33
{
34
  MemoryCounter()
35
    : mSource(0)
36
    , mDecodedHeap(0)
37
    , mDecodedNonHeap(0)
38
    , mExternalHandles(0)
39
0
  { }
40
41
0
  void SetSource(size_t aCount) { mSource = aCount; }
42
0
  size_t Source() const { return mSource; }
43
0
  void SetDecodedHeap(size_t aCount) { mDecodedHeap = aCount; }
44
0
  size_t DecodedHeap() const { return mDecodedHeap; }
45
0
  void SetDecodedNonHeap(size_t aCount) { mDecodedNonHeap = aCount; }
46
0
  size_t DecodedNonHeap() const { return mDecodedNonHeap; }
47
0
  void SetExternalHandles(size_t aCount) { mExternalHandles = aCount; }
48
0
  size_t ExternalHandles() const { return mExternalHandles; }
49
50
  MemoryCounter& operator+=(const MemoryCounter& aOther)
51
0
  {
52
0
    mSource += aOther.mSource;
53
0
    mDecodedHeap += aOther.mDecodedHeap;
54
0
    mDecodedNonHeap += aOther.mDecodedNonHeap;
55
0
    mExternalHandles += aOther.mExternalHandles;
56
0
    return *this;
57
0
  }
58
59
private:
60
  size_t mSource;
61
  size_t mDecodedHeap;
62
  size_t mDecodedNonHeap;
63
  size_t mExternalHandles;
64
};
65
66
enum class SurfaceMemoryCounterType
67
{
68
  NORMAL,
69
  COMPOSITING,
70
  COMPOSITING_PREV
71
};
72
73
struct SurfaceMemoryCounter
74
{
75
  SurfaceMemoryCounter(const SurfaceKey& aKey,
76
                       bool aIsLocked,
77
                       bool aCannotSubstitute,
78
                       bool aIsFactor2,
79
                       SurfaceMemoryCounterType aType =
80
                         SurfaceMemoryCounterType::NORMAL)
81
    : mKey(aKey)
82
    , mType(aType)
83
    , mIsLocked(aIsLocked)
84
    , mCannotSubstitute(aCannotSubstitute)
85
    , mIsFactor2(aIsFactor2)
86
0
  { }
87
88
0
  const SurfaceKey& Key() const { return mKey; }
89
0
  MemoryCounter& Values() { return mValues; }
90
0
  const MemoryCounter& Values() const { return mValues; }
91
0
  SurfaceMemoryCounterType Type() const { return mType; }
92
0
  bool IsLocked() const { return mIsLocked; }
93
0
  bool CannotSubstitute() const { return mCannotSubstitute; }
94
0
  bool IsFactor2() const { return mIsFactor2; }
95
96
private:
97
  const SurfaceKey mKey;
98
  MemoryCounter mValues;
99
  const SurfaceMemoryCounterType mType;
100
  const bool mIsLocked;
101
  const bool mCannotSubstitute;
102
  const bool mIsFactor2;
103
};
104
105
struct ImageMemoryCounter
106
{
107
  ImageMemoryCounter(Image* aImage, SizeOfState& aState, bool aIsUsed);
108
109
0
  nsCString& URI() { return mURI; }
110
0
  const nsCString& URI() const { return mURI; }
111
0
  const nsTArray<SurfaceMemoryCounter>& Surfaces() const { return mSurfaces; }
112
0
  const gfx::IntSize IntrinsicSize() const { return mIntrinsicSize; }
113
0
  const MemoryCounter& Values() const { return mValues; }
114
0
  uint16_t Type() const { return mType; }
115
0
  bool IsUsed() const { return mIsUsed; }
116
117
  bool IsNotable() const
118
0
  {
119
0
    const size_t NotableThreshold = 16 * 1024;
120
0
    size_t total = mValues.Source() + mValues.DecodedHeap()
121
0
                                    + mValues.DecodedNonHeap();
122
0
    return total >= NotableThreshold;
123
0
  }
124
125
private:
126
  nsCString mURI;
127
  nsTArray<SurfaceMemoryCounter> mSurfaces;
128
  gfx::IntSize mIntrinsicSize;
129
  MemoryCounter mValues;
130
  uint16_t mType;
131
  const bool mIsUsed;
132
};
133
134
135
///////////////////////////////////////////////////////////////////////////////
136
// Image Base Types
137
///////////////////////////////////////////////////////////////////////////////
138
139
class Image : public imgIContainer
140
{
141
public:
142
  /**
143
   * Flags for Image initialization.
144
   *
145
   * Meanings:
146
   *
147
   * INIT_FLAG_NONE: Lack of flags
148
   *
149
   * INIT_FLAG_DISCARDABLE: The container should be discardable
150
   *
151
   * INIT_FLAG_DECODE_IMMEDIATELY: The container should decode as soon as
152
   * possible, regardless of what our heuristics say.
153
   *
154
   * INIT_FLAG_TRANSIENT: The container is likely to exist for only a short time
155
   * before being destroyed. (For example, containers for
156
   * multipart/x-mixed-replace image parts fall into this category.) If this
157
   * flag is set, INIT_FLAG_DISCARDABLE and INIT_FLAG_DECODE_ONLY_ON_DRAW must
158
   * not be set.
159
   *
160
   * INIT_FLAG_SYNC_LOAD: The container is being loaded synchronously, so
161
   * it should avoid relying on async workers to get the container ready.
162
   */
163
  static const uint32_t INIT_FLAG_NONE                     = 0x0;
164
  static const uint32_t INIT_FLAG_DISCARDABLE              = 0x1;
165
  static const uint32_t INIT_FLAG_DECODE_IMMEDIATELY       = 0x2;
166
  static const uint32_t INIT_FLAG_TRANSIENT                = 0x4;
167
  static const uint32_t INIT_FLAG_SYNC_LOAD                = 0x8;
168
169
  virtual already_AddRefed<ProgressTracker> GetProgressTracker() = 0;
170
0
  virtual void SetProgressTracker(ProgressTracker* aProgressTracker) {}
171
172
  /**
173
   * The size, in bytes, occupied by the compressed source data of the image.
174
   * If MallocSizeOf does not work on this platform, uses a fallback approach to
175
   * ensure that something reasonable is always returned.
176
   */
177
  virtual size_t
178
    SizeOfSourceWithComputedFallback(SizeOfState& aState) const = 0;
179
180
  /**
181
   * Collect an accounting of the memory occupied by the image's surfaces (which
182
   * together make up its decoded data). Each surface is recorded as a separate
183
   * SurfaceMemoryCounter, stored in @aCounters.
184
   */
185
  virtual void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters,
186
                                     MallocSizeOf aMallocSizeOf) const = 0;
187
188
  virtual void IncrementAnimationConsumers() = 0;
189
  virtual void DecrementAnimationConsumers() = 0;
190
#ifdef DEBUG
191
  virtual uint32_t GetAnimationConsumers() = 0;
192
#endif
193
194
  /**
195
   * Called from OnDataAvailable when the stream associated with the image has
196
   * received new image data. The arguments are the same as OnDataAvailable's,
197
   * but by separating this functionality into a different method we don't
198
   * interfere with subclasses which wish to implement nsIStreamListener.
199
   *
200
   * Images should not do anything that could send out notifications until they
201
   * have received their first OnImageDataAvailable notification; in
202
   * particular, this means that instantiating decoders should be deferred
203
   * until OnImageDataAvailable is called.
204
   */
205
  virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
206
                                        nsISupports* aContext,
207
                                        nsIInputStream* aInStr,
208
                                        uint64_t aSourceOffset,
209
                                        uint32_t aCount) = 0;
210
211
  /**
212
   * Called from OnStopRequest when the image's underlying request completes.
213
   *
214
   * @param aRequest  The completed request.
215
   * @param aContext  Context from Necko's OnStopRequest.
216
   * @param aStatus   A success or failure code.
217
   * @param aLastPart Whether this is the final part of the underlying request.
218
   */
219
  virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
220
                                       nsISupports* aContext,
221
                                       nsresult aStatus,
222
                                       bool aLastPart) = 0;
223
224
  /**
225
   * Called when the SurfaceCache discards a surface belonging to this image.
226
   */
227
  virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) = 0;
228
229
  virtual void SetInnerWindowID(uint64_t aInnerWindowId) = 0;
230
  virtual uint64_t InnerWindowID() const = 0;
231
232
  virtual bool HasError() = 0;
233
  virtual void SetHasError() = 0;
234
235
  virtual nsIURI* GetURI() const = 0;
236
237
0
  virtual void ReportUseCounters() { }
238
};
239
240
class ImageResource : public Image
241
{
242
public:
243
  already_AddRefed<ProgressTracker> GetProgressTracker() override
244
0
  {
245
0
    RefPtr<ProgressTracker> progressTracker = mProgressTracker;
246
0
    MOZ_ASSERT(progressTracker);
247
0
    return progressTracker.forget();
248
0
  }
249
250
  void SetProgressTracker(ProgressTracker* aProgressTracker) final
251
0
  {
252
0
    MOZ_ASSERT(aProgressTracker);
253
0
    MOZ_ASSERT(!mProgressTracker);
254
0
    mProgressTracker = aProgressTracker;
255
0
  }
256
257
  virtual void IncrementAnimationConsumers() override;
258
  virtual void DecrementAnimationConsumers() override;
259
#ifdef DEBUG
260
  virtual uint32_t GetAnimationConsumers() override
261
  {
262
    return mAnimationConsumers;
263
  }
264
#endif
265
266
0
  virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) override { }
267
268
  virtual void SetInnerWindowID(uint64_t aInnerWindowId) override
269
0
  {
270
0
    mInnerWindowId = aInnerWindowId;
271
0
  }
272
0
  virtual uint64_t InnerWindowID() const override { return mInnerWindowId; }
273
274
0
  virtual bool HasError() override    { return mError; }
275
0
  virtual void SetHasError() override { mError = true; }
276
277
  /*
278
   * Returns a non-AddRefed pointer to the URI associated with this image.
279
   * Illegal to use off-main-thread.
280
   */
281
0
  nsIURI* GetURI() const override { return mURI; }
282
283
protected:
284
  explicit ImageResource(nsIURI* aURI);
285
  ~ImageResource();
286
287
  bool GetSpecTruncatedTo1k(nsCString& aSpec) const;
288
289
  // Shared functionality for implementors of imgIContainer. Every
290
  // implementation of attribute animationMode should forward here.
291
  nsresult GetAnimationModeInternal(uint16_t* aAnimationMode);
292
  nsresult SetAnimationModeInternal(uint16_t aAnimationMode);
293
294
  /**
295
   * Helper for RequestRefresh.
296
   *
297
   * If we've had a "recent" refresh (i.e. if this image is being used in
298
   * multiple documents & some other document *just* called RequestRefresh() on
299
   * this image with a timestamp close to aTime), this method returns true.
300
   *
301
   * Otherwise, this method updates mLastRefreshTime to aTime & returns false.
302
   */
303
  bool HadRecentRefresh(const TimeStamp& aTime);
304
305
  /**
306
   * Decides whether animation should or should not be happening,
307
   * and makes sure the right thing is being done.
308
   */
309
  virtual void EvaluateAnimation();
310
311
  /**
312
   * Extended by child classes, if they have additional
313
   * conditions for being able to animate.
314
   */
315
0
  virtual bool ShouldAnimate() {
316
0
    return mAnimationConsumers > 0 && mAnimationMode != kDontAnimMode;
317
0
  }
318
319
  virtual nsresult StartAnimation() = 0;
320
  virtual nsresult StopAnimation() = 0;
321
322
  void SendOnUnlockedDraw(uint32_t aFlags);
323
324
#ifdef DEBUG
325
  // Records the image drawing for startup performance testing.
326
  void NotifyDrawingObservers();
327
#endif
328
329
  // Member data shared by all implementations of this abstract class
330
  RefPtr<ProgressTracker>       mProgressTracker;
331
  nsCOMPtr<nsIURI>              mURI;
332
  TimeStamp                     mLastRefreshTime;
333
  uint64_t                      mInnerWindowId;
334
  uint32_t                      mAnimationConsumers;
335
  uint16_t                      mAnimationMode; // Enum values in imgIContainer
336
  bool                          mInitialized:1; // Have we been initalized?
337
  bool                          mAnimating:1;   // Are we currently animating?
338
  bool                          mError:1;       // Error handling
339
340
  /**
341
   * Attempt to find a matching cached surface in the SurfaceCache, and if not
342
   * available, request the production of such a surface (either synchronously
343
   * or asynchronously).
344
   *
345
   * If the draw result is BAD_IMAGE, BAD_ARGS or NOT_READY, the size will be
346
   * the same as aSize. If it is TEMPORARY_ERROR, INCOMPLETE, or SUCCESS, the
347
   * size is a hint as to what we expect the surface size to be, once the best
348
   * fitting size is available. It may or may not match the size of the surface
349
   * returned at this moment. This is useful for choosing how to store the final
350
   * result (e.g. if going into an ImageContainer, ideally we would share the
351
   * same container for many requested sizes, if they all end up with the same
352
   * best fit size in the end).
353
   *
354
   * A valid surface should only be returned for SUCCESS and INCOMPLETE.
355
   *
356
   * Any other draw result is invalid.
357
   */
358
  virtual Tuple<ImgDrawResult, gfx::IntSize, RefPtr<gfx::SourceSurface>>
359
    GetFrameInternal(const gfx::IntSize& aSize,
360
                     const Maybe<SVGImageContext>& aSVGContext,
361
                     uint32_t aWhichFrame,
362
                     uint32_t aFlags)
363
0
  {
364
0
    return MakeTuple(ImgDrawResult::BAD_IMAGE, aSize,
365
0
                     RefPtr<gfx::SourceSurface>());
366
0
  }
367
368
  /**
369
   * Calculate the estimated size to use for an image container with the given
370
   * parameters. It may not be the same as the given size, and it may not be
371
   * the same as the size of the surface in the image container, but it is the
372
   * best effort estimate.
373
   */
374
  virtual Tuple<ImgDrawResult, gfx::IntSize>
375
    GetImageContainerSize(layers::LayerManager* aManager,
376
                          const gfx::IntSize& aSize,
377
                          uint32_t aFlags)
378
0
  {
379
0
    return MakeTuple(ImgDrawResult::NOT_SUPPORTED, gfx::IntSize(0, 0));
380
0
  }
381
382
  ImgDrawResult GetImageContainerImpl(layers::LayerManager* aManager,
383
                                      const gfx::IntSize& aSize,
384
                                      const Maybe<SVGImageContext>& aSVGContext,
385
                                      uint32_t aFlags,
386
                                      layers::ImageContainer** aContainer);
387
388
  void UpdateImageContainer();
389
390
  void ReleaseImageContainer();
391
392
private:
393
  void SetCurrentImage(layers::ImageContainer* aContainer,
394
                       gfx::SourceSurface* aSurface,
395
                       bool aInTransaction);
396
397
  struct ImageContainerEntry {
398
    ImageContainerEntry(const gfx::IntSize& aSize,
399
                        const Maybe<SVGImageContext>& aSVGContext,
400
                        layers::ImageContainer* aContainer,
401
                        uint32_t aFlags)
402
      : mSize(aSize)
403
      , mSVGContext(aSVGContext)
404
      , mContainer(aContainer)
405
      , mLastDrawResult(ImgDrawResult::NOT_READY)
406
      , mFlags(aFlags)
407
0
    { }
408
409
    gfx::IntSize                        mSize;
410
    Maybe<SVGImageContext>              mSVGContext;
411
    // A weak pointer to our ImageContainer, which stays alive only as long as
412
    // the layer system needs it.
413
    WeakPtr<layers::ImageContainer>     mContainer;
414
    // If mContainer is non-null, this contains the ImgDrawResult we obtained
415
    // the last time we updated it.
416
    ImgDrawResult                          mLastDrawResult;
417
    // Cached flags to use for decoding. FLAG_ASYNC_NOTIFY should always be set
418
    // but FLAG_HIGH_QUALITY_SCALING may vary.
419
    uint32_t                            mFlags;
420
  };
421
422
  AutoTArray<ImageContainerEntry, 1> mImageContainers;
423
  layers::ImageContainer::ProducerID mImageProducerID;
424
  layers::ImageContainer::FrameID mLastFrameID;
425
};
426
427
} // namespace image
428
} // namespace mozilla
429
430
#endif // mozilla_image_Image_h