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/TimeStamp.h"
11 #include "gfx2DGlue.h"
12 #include "imgIContainer.h"
13 #include "ImageURL.h"
14 #include "nsStringFwd.h"
15 #include "ProgressTracker.h"
16 #include "SurfaceCache.h"
17 
18 class nsIRequest;
19 class nsIInputStream;
20 
21 namespace mozilla {
22 namespace image {
23 
24 class Image;
25 
26 ///////////////////////////////////////////////////////////////////////////////
27 // Memory Reporting
28 ///////////////////////////////////////////////////////////////////////////////
29 
30 struct MemoryCounter
31 {
32   MemoryCounter()
33     : mSource(0)
34     , mDecodedHeap(0)
35     , mDecodedNonHeap(0)
36   { }
37 
38   void SetSource(size_t aCount) { mSource = aCount; }
39   size_t Source() const { return mSource; }
40   void SetDecodedHeap(size_t aCount) { mDecodedHeap = aCount; }
41   size_t DecodedHeap() const { return mDecodedHeap; }
42   void SetDecodedNonHeap(size_t aCount) { mDecodedNonHeap = aCount; }
43   size_t DecodedNonHeap() const { return mDecodedNonHeap; }
44 
45   MemoryCounter& operator+=(const MemoryCounter& aOther)
46   {
47     mSource += aOther.mSource;
48     mDecodedHeap += aOther.mDecodedHeap;
49     mDecodedNonHeap += aOther.mDecodedNonHeap;
50     return *this;
51   }
52 
53 private:
54   size_t mSource;
55   size_t mDecodedHeap;
56   size_t mDecodedNonHeap;
57 };
58 
59 enum class SurfaceMemoryCounterType
60 {
61   NORMAL,
62   COMPOSITING,
63   COMPOSITING_PREV
64 };
65 
66 struct SurfaceMemoryCounter
67 {
68   SurfaceMemoryCounter(const SurfaceKey& aKey,
69                        bool aIsLocked,
70                        SurfaceMemoryCounterType aType =
71                          SurfaceMemoryCounterType::NORMAL)
72     : mKey(aKey)
73     , mType(aType)
74     , mIsLocked(aIsLocked)
75   { }
76 
77   const SurfaceKey& Key() const { return mKey; }
78   MemoryCounter& Values() { return mValues; }
79   const MemoryCounter& Values() const { return mValues; }
80   SurfaceMemoryCounterType Type() const { return mType; }
81   bool IsLocked() const { return mIsLocked; }
82 
83 private:
84   const SurfaceKey mKey;
85   MemoryCounter mValues;
86   const SurfaceMemoryCounterType mType;
87   const bool mIsLocked;
88 };
89 
90 struct ImageMemoryCounter
91 {
92   ImageMemoryCounter(Image* aImage,
93                      MallocSizeOf aMallocSizeOf,
94                      bool aIsUsed);
95 
96   nsCString& URI() { return mURI; }
97   const nsCString& URI() const { return mURI; }
98   const nsTArray<SurfaceMemoryCounter>& Surfaces() const { return mSurfaces; }
99   const gfx::IntSize IntrinsicSize() const { return mIntrinsicSize; }
100   const MemoryCounter& Values() const { return mValues; }
101   uint16_t Type() const { return mType; }
102   bool IsUsed() const { return mIsUsed; }
103 
104   bool IsNotable() const
105   {
106     const size_t NotableThreshold = 16 * 1024;
107     size_t total = mValues.Source() + mValues.DecodedHeap()
108                                     + mValues.DecodedNonHeap();
109     return total >= NotableThreshold;
110   }
111 
112 private:
113   nsCString mURI;
114   nsTArray<SurfaceMemoryCounter> mSurfaces;
115   gfx::IntSize mIntrinsicSize;
116   MemoryCounter mValues;
117   uint16_t mType;
118   const bool mIsUsed;
119 };
120 
121 
122 ///////////////////////////////////////////////////////////////////////////////
123 // Image Base Types
124 ///////////////////////////////////////////////////////////////////////////////
125 
126 class Image : public imgIContainer
127 {
128 public:
129   /**
130    * Flags for Image initialization.
131    *
132    * Meanings:
133    *
134    * INIT_FLAG_NONE: Lack of flags
135    *
136    * INIT_FLAG_DISCARDABLE: The container should be discardable
137    *
138    * INIT_FLAG_DECODE_IMMEDIATELY: The container should decode as soon as
139    * possible, regardless of what our heuristics say.
140    *
141    * INIT_FLAG_TRANSIENT: The container is likely to exist for only a short time
142    * before being destroyed. (For example, containers for
143    * multipart/x-mixed-replace image parts fall into this category.) If this
144    * flag is set, INIT_FLAG_DISCARDABLE and INIT_FLAG_DECODE_ONLY_ON_DRAW must
145    * not be set.
146    *
147    * INIT_FLAG_SYNC_LOAD: The container is being loaded synchronously, so
148    * it should avoid relying on async workers to get the container ready.
149    */
150   static const uint32_t INIT_FLAG_NONE                     = 0x0;
151   static const uint32_t INIT_FLAG_DISCARDABLE              = 0x1;
152   static const uint32_t INIT_FLAG_DECODE_IMMEDIATELY       = 0x2;
153   static const uint32_t INIT_FLAG_TRANSIENT                = 0x4;
154   static const uint32_t INIT_FLAG_SYNC_LOAD                = 0x8;
155 
156   virtual already_AddRefed<ProgressTracker> GetProgressTracker() = 0;
157   virtual void SetProgressTracker(ProgressTracker* aProgressTracker) {}
158 
159   /**
160    * The size, in bytes, occupied by the compressed source data of the image.
161    * If MallocSizeOf does not work on this platform, uses a fallback approach to
162    * ensure that something reasonable is always returned.
163    */
164   virtual size_t
165     SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const = 0;
166 
167   /**
168    * Collect an accounting of the memory occupied by the image's surfaces (which
169    * together make up its decoded data). Each surface is recorded as a separate
170    * SurfaceMemoryCounter, stored in @aCounters.
171    */
172   virtual void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters,
173                                      MallocSizeOf aMallocSizeOf) const = 0;
174 
175   virtual void IncrementAnimationConsumers() = 0;
176   virtual void DecrementAnimationConsumers() = 0;
177 #ifdef DEBUG
178   virtual uint32_t GetAnimationConsumers() = 0;
179 #endif
180 
181   /**
182    * Called from OnDataAvailable when the stream associated with the image has
183    * received new image data. The arguments are the same as OnDataAvailable's,
184    * but by separating this functionality into a different method we don't
185    * interfere with subclasses which wish to implement nsIStreamListener.
186    *
187    * Images should not do anything that could send out notifications until they
188    * have received their first OnImageDataAvailable notification; in
189    * particular, this means that instantiating decoders should be deferred
190    * until OnImageDataAvailable is called.
191    */
192   virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
193                                         nsISupports* aContext,
194                                         nsIInputStream* aInStr,
195                                         uint64_t aSourceOffset,
196                                         uint32_t aCount) = 0;
197 
198   /**
199    * Called from OnStopRequest when the image's underlying request completes.
200    *
201    * @param aRequest  The completed request.
202    * @param aContext  Context from Necko's OnStopRequest.
203    * @param aStatus   A success or failure code.
204    * @param aLastPart Whether this is the final part of the underlying request.
205    */
206   virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
207                                        nsISupports* aContext,
208                                        nsresult aStatus,
209                                        bool aLastPart) = 0;
210 
211   /**
212    * Called when the SurfaceCache discards a surface belonging to this image.
213    */
214   virtual void OnSurfaceDiscarded() = 0;
215 
216   virtual void SetInnerWindowID(uint64_t aInnerWindowId) = 0;
217   virtual uint64_t InnerWindowID() const = 0;
218 
219   virtual bool HasError() = 0;
220   virtual void SetHasError() = 0;
221 
222   virtual ImageURL* GetURI() = 0;
223 
224   virtual void ReportUseCounters() { }
225 };
226 
227 class ImageResource : public Image
228 {
229 public:
230   already_AddRefed<ProgressTracker> GetProgressTracker() override
231   {
232     RefPtr<ProgressTracker> progressTracker = mProgressTracker;
233     MOZ_ASSERT(progressTracker);
234     return progressTracker.forget();
235   }
236 
237   void SetProgressTracker(
238                        ProgressTracker* aProgressTracker) override final
239   {
240     MOZ_ASSERT(aProgressTracker);
241     MOZ_ASSERT(!mProgressTracker);
242     mProgressTracker = aProgressTracker;
243   }
244 
245   virtual void IncrementAnimationConsumers() override;
246   virtual void DecrementAnimationConsumers() override;
247 #ifdef DEBUG
248   virtual uint32_t GetAnimationConsumers() override
249   {
250     return mAnimationConsumers;
251   }
252 #endif
253 
254   virtual void OnSurfaceDiscarded() override { }
255 
256   virtual void SetInnerWindowID(uint64_t aInnerWindowId) override
257   {
258     mInnerWindowId = aInnerWindowId;
259   }
260   virtual uint64_t InnerWindowID() const override { return mInnerWindowId; }
261 
262   virtual bool HasError() override    { return mError; }
263   virtual void SetHasError() override { mError = true; }
264 
265   /*
266    * Returns a non-AddRefed pointer to the URI associated with this image.
267    * Illegal to use off-main-thread.
268    */
269   virtual ImageURL* GetURI() override { return mURI.get(); }
270 
271 protected:
272   explicit ImageResource(ImageURL* aURI);
273   ~ImageResource();
274 
275   // Shared functionality for implementors of imgIContainer. Every
276   // implementation of attribute animationMode should forward here.
277   nsresult GetAnimationModeInternal(uint16_t* aAnimationMode);
278   nsresult SetAnimationModeInternal(uint16_t aAnimationMode);
279 
280   /**
281    * Helper for RequestRefresh.
282    *
283    * If we've had a "recent" refresh (i.e. if this image is being used in
284    * multiple documents & some other document *just* called RequestRefresh() on
285    * this image with a timestamp close to aTime), this method returns true.
286    *
287    * Otherwise, this method updates mLastRefreshTime to aTime & returns false.
288    */
289   bool HadRecentRefresh(const TimeStamp& aTime);
290 
291   /**
292    * Decides whether animation should or should not be happening,
293    * and makes sure the right thing is being done.
294    */
295   virtual void EvaluateAnimation();
296 
297   /**
298    * Extended by child classes, if they have additional
299    * conditions for being able to animate.
300    */
301   virtual bool ShouldAnimate() {
302     return mAnimationConsumers > 0 && mAnimationMode != kDontAnimMode;
303   }
304 
305   virtual nsresult StartAnimation() = 0;
306   virtual nsresult StopAnimation() = 0;
307 
308   // Member data shared by all implementations of this abstract class
309   RefPtr<ProgressTracker>     mProgressTracker;
310   RefPtr<ImageURL>            mURI;
311   TimeStamp                     mLastRefreshTime;
312   uint64_t                      mInnerWindowId;
313   uint32_t                      mAnimationConsumers;
314   uint16_t                      mAnimationMode; // Enum values in imgIContainer
315   bool                          mInitialized:1; // Have we been initalized?
316   bool                          mAnimating:1;   // Are we currently animating?
317   bool                          mError:1;       // Error handling
318 };
319 
320 } // namespace image
321 } // namespace mozilla
322 
323 #endif // mozilla_image_Image_h
324