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/. */
6 #ifndef mozilla_image_Image_h
7 #define mozilla_image_Image_h
9 #include "mozilla/Attributes.h"
10 #include "mozilla/Maybe.h"
11 #include "mozilla/MemoryReporting.h"
12 #include "mozilla/ProfilerMarkers.h"
13 #include "mozilla/SizeOfState.h"
14 #include "mozilla/ThreadSafeWeakPtr.h"
15 #include "mozilla/TimeStamp.h"
17 #include "gfx2DGlue.h"
18 #include "imgIContainer.h"
19 #include "ImageContainer.h"
20 #include "ImageRegion.h"
21 #include "LookupResult.h"
22 #include "nsStringFwd.h"
23 #include "ProgressTracker.h"
24 #include "SurfaceCache.h"
25 #include "WebRenderImageProvider.h"
36 ///////////////////////////////////////////////////////////////////////////////
38 ///////////////////////////////////////////////////////////////////////////////
40 struct MemoryCounter
{
51 void SetSource(size_t aCount
) { mSource
= aCount
; }
52 size_t Source() const { return mSource
; }
53 void SetDecodedHeap(size_t aCount
) { mDecodedHeap
= aCount
; }
54 size_t DecodedHeap() const { return mDecodedHeap
; }
55 void SetDecodedNonHeap(size_t aCount
) { mDecodedNonHeap
= aCount
; }
56 size_t DecodedNonHeap() const { return mDecodedNonHeap
; }
57 void SetDecodedUnknown(size_t aCount
) { mDecodedUnknown
= aCount
; }
58 size_t DecodedUnknown() const { return mDecodedUnknown
; }
59 void SetExternalHandles(size_t aCount
) { mExternalHandles
= aCount
; }
60 size_t ExternalHandles() const { return mExternalHandles
; }
61 void SetFrameIndex(size_t aIndex
) { mFrameIndex
= aIndex
; }
62 size_t FrameIndex() const { return mFrameIndex
; }
63 void SetExternalId(uint64_t aId
) { mExternalId
= aId
; }
64 uint64_t ExternalId() const { return mExternalId
; }
65 void SetSurfaceTypes(uint32_t aTypes
) { mSurfaceTypes
= aTypes
; }
66 uint32_t SurfaceTypes() const { return mSurfaceTypes
; }
68 MemoryCounter
& operator+=(const MemoryCounter
& aOther
) {
69 mSource
+= aOther
.mSource
;
70 mDecodedHeap
+= aOther
.mDecodedHeap
;
71 mDecodedNonHeap
+= aOther
.mDecodedNonHeap
;
72 mDecodedUnknown
+= aOther
.mDecodedUnknown
;
73 mExternalHandles
+= aOther
.mExternalHandles
;
74 mSurfaceTypes
|= aOther
.mSurfaceTypes
;
81 size_t mDecodedNonHeap
;
82 size_t mDecodedUnknown
;
83 size_t mExternalHandles
;
86 uint32_t mSurfaceTypes
;
89 enum class SurfaceMemoryCounterType
{ NORMAL
, CONTAINER
};
91 struct SurfaceMemoryCounter
{
93 const SurfaceKey
& aKey
, bool aIsLocked
, bool aCannotSubstitute
,
94 bool aIsFactor2
, bool aFinished
,
95 SurfaceMemoryCounterType aType
= SurfaceMemoryCounterType::NORMAL
)
99 mCannotSubstitute(aCannotSubstitute
),
100 mIsFactor2(aIsFactor2
),
101 mFinished(aFinished
) {}
103 const SurfaceKey
& Key() const { return mKey
; }
104 MemoryCounter
& Values() { return mValues
; }
105 const MemoryCounter
& Values() const { return mValues
; }
106 SurfaceMemoryCounterType
Type() const { return mType
; }
107 bool IsLocked() const { return mIsLocked
; }
108 bool CannotSubstitute() const { return mCannotSubstitute
; }
109 bool IsFactor2() const { return mIsFactor2
; }
110 bool IsFinished() const { return mFinished
; }
113 const SurfaceKey mKey
;
114 MemoryCounter mValues
;
115 const SurfaceMemoryCounterType mType
;
116 const bool mIsLocked
;
117 const bool mCannotSubstitute
;
118 const bool mIsFactor2
;
119 const bool mFinished
;
122 struct ImageMemoryCounter
{
123 ImageMemoryCounter(imgRequest
* aRequest
, SizeOfState
& aState
, bool aIsUsed
);
124 ImageMemoryCounter(imgRequest
* aRequest
, Image
* aImage
, SizeOfState
& aState
,
127 nsCString
& URI() { return mURI
; }
128 const nsCString
& URI() const { return mURI
; }
129 const nsTArray
<SurfaceMemoryCounter
>& Surfaces() const { return mSurfaces
; }
130 const gfx::IntSize
IntrinsicSize() const { return mIntrinsicSize
; }
131 const MemoryCounter
& Values() const { return mValues
; }
132 uint32_t Progress() const { return mProgress
; }
133 uint16_t Type() const { return mType
; }
134 bool IsUsed() const { return mIsUsed
; }
135 bool HasError() const { return mHasError
; }
136 bool IsValidating() const { return mValidating
; }
138 bool IsNotable() const {
139 // Errors or requests without images are always notable.
140 if (mHasError
|| mValidating
|| mProgress
== UINT32_MAX
||
141 mProgress
& FLAG_HAS_ERROR
|| mType
== imgIContainer::TYPE_REQUEST
) {
145 // Sufficiently large images are notable.
146 const size_t NotableThreshold
= 16 * 1024;
147 size_t total
= mValues
.Source() + mValues
.DecodedHeap() +
148 mValues
.DecodedNonHeap() + mValues
.DecodedUnknown();
149 if (total
>= NotableThreshold
) {
153 // Incomplete images are always notable as well; the odds of capturing
154 // mid-decode should be fairly low.
155 for (const auto& surface
: mSurfaces
) {
156 if (!surface
.IsFinished()) {
166 nsTArray
<SurfaceMemoryCounter
> mSurfaces
;
167 gfx::IntSize mIntrinsicSize
;
168 MemoryCounter mValues
;
176 ///////////////////////////////////////////////////////////////////////////////
178 ///////////////////////////////////////////////////////////////////////////////
180 class Image
: public imgIContainer
{
183 * Flags for Image initialization.
187 * INIT_FLAG_NONE: Lack of flags
189 * INIT_FLAG_DISCARDABLE: The container should be discardable
191 * INIT_FLAG_DECODE_IMMEDIATELY: The container should decode as soon as
192 * possible, regardless of what our heuristics say.
194 * INIT_FLAG_TRANSIENT: The container is likely to exist for only a short time
195 * before being destroyed. (For example, containers for
196 * multipart/x-mixed-replace image parts fall into this category.) If this
197 * flag is set, INIT_FLAG_DISCARDABLE and INIT_FLAG_DECODE_ONLY_ON_DRAW must
200 * INIT_FLAG_SYNC_LOAD: The container is being loaded synchronously, so
201 * it should avoid relying on async workers to get the container ready.
203 static const uint32_t INIT_FLAG_NONE
= 0x0;
204 static const uint32_t INIT_FLAG_DISCARDABLE
= 0x1;
205 static const uint32_t INIT_FLAG_DECODE_IMMEDIATELY
= 0x2;
206 static const uint32_t INIT_FLAG_TRANSIENT
= 0x4;
207 static const uint32_t INIT_FLAG_SYNC_LOAD
= 0x8;
209 virtual already_AddRefed
<ProgressTracker
> GetProgressTracker() = 0;
210 virtual void SetProgressTracker(ProgressTracker
* aProgressTracker
) {}
213 * The size, in bytes, occupied by the compressed source data of the image.
214 * If MallocSizeOf does not work on this platform, uses a fallback approach to
215 * ensure that something reasonable is always returned.
217 virtual size_t SizeOfSourceWithComputedFallback(
218 SizeOfState
& aState
) const = 0;
221 * Collect an accounting of the memory occupied by the image's surfaces (which
222 * together make up its decoded data). Each surface is recorded as a separate
223 * SurfaceMemoryCounter, stored in @aCounters.
225 virtual void CollectSizeOfSurfaces(nsTArray
<SurfaceMemoryCounter
>& aCounters
,
226 MallocSizeOf aMallocSizeOf
) const = 0;
228 virtual void IncrementAnimationConsumers() = 0;
229 virtual void DecrementAnimationConsumers() = 0;
231 virtual uint32_t GetAnimationConsumers() = 0;
235 * Called from OnDataAvailable when the stream associated with the image has
236 * received new image data. The arguments are the same as OnDataAvailable's,
237 * but by separating this functionality into a different method we don't
238 * interfere with subclasses which wish to implement nsIStreamListener.
240 * Images should not do anything that could send out notifications until they
241 * have received their first OnImageDataAvailable notification; in
242 * particular, this means that instantiating decoders should be deferred
243 * until OnImageDataAvailable is called.
245 virtual nsresult
OnImageDataAvailable(nsIRequest
* aRequest
,
246 nsIInputStream
* aInStr
,
247 uint64_t aSourceOffset
,
248 uint32_t aCount
) = 0;
251 * Called from OnStopRequest when the image's underlying request completes.
253 * @param aRequest The completed request.
254 * @param aStatus A success or failure code.
255 * @param aLastPart Whether this is the final part of the underlying request.
257 virtual nsresult
OnImageDataComplete(nsIRequest
* aRequest
, nsresult aStatus
,
261 * Called when the SurfaceCache discards a surface belonging to this image.
263 virtual void OnSurfaceDiscarded(const SurfaceKey
& aSurfaceKey
) = 0;
265 virtual void SetInnerWindowID(uint64_t aInnerWindowId
) = 0;
266 virtual uint64_t InnerWindowID() const = 0;
268 virtual bool HasError() = 0;
269 virtual void SetHasError() = 0;
271 virtual nsIURI
* GetURI() const = 0;
273 NS_IMETHOD
GetHotspotX(int32_t* aX
) override
{
277 NS_IMETHOD
GetHotspotY(int32_t* aY
) override
{
283 class ImageResource
: public Image
{
285 already_AddRefed
<ProgressTracker
> GetProgressTracker() override
{
286 RefPtr
<ProgressTracker
> progressTracker
= mProgressTracker
;
287 MOZ_ASSERT(progressTracker
);
288 return progressTracker
.forget();
291 void SetProgressTracker(ProgressTracker
* aProgressTracker
) final
{
292 MOZ_ASSERT(aProgressTracker
);
293 MOZ_ASSERT(!mProgressTracker
);
294 mProgressTracker
= aProgressTracker
;
297 virtual void IncrementAnimationConsumers() override
;
298 virtual void DecrementAnimationConsumers() override
;
300 virtual uint32_t GetAnimationConsumers() override
{
301 return mAnimationConsumers
;
305 virtual void OnSurfaceDiscarded(const SurfaceKey
& aSurfaceKey
) override
{}
307 virtual void SetInnerWindowID(uint64_t aInnerWindowId
) override
{
308 mInnerWindowId
= aInnerWindowId
;
310 virtual uint64_t InnerWindowID() const override
{ return mInnerWindowId
; }
312 virtual bool HasError() override
{ return mError
; }
313 virtual void SetHasError() override
{ mError
= true; }
316 * Returns a non-AddRefed pointer to the URI associated with this image.
317 * Illegal to use off-main-thread.
319 nsIURI
* GetURI() const override
{ return mURI
; }
322 * Should be called by its subclasses after they populate @aCounters so that
323 * we can cross reference against any of our ImageContainers that contain
324 * surfaces not in the cache.
326 void CollectSizeOfSurfaces(nsTArray
<SurfaceMemoryCounter
>& aCounters
,
327 MallocSizeOf aMallocSizeOf
) const override
;
329 ImageProviderId
GetImageProviderId() const { return mProviderId
; }
332 explicit ImageResource(nsIURI
* aURI
);
335 bool GetSpecTruncatedTo1k(nsCString
& aSpec
) const;
337 // Shared functionality for implementors of imgIContainer. Every
338 // implementation of attribute animationMode should forward here.
339 nsresult
GetAnimationModeInternal(uint16_t* aAnimationMode
);
340 nsresult
SetAnimationModeInternal(uint16_t aAnimationMode
);
343 * Helper for RequestRefresh.
345 * If we've had a "recent" refresh (i.e. if this image is being used in
346 * multiple documents & some other document *just* called RequestRefresh() on
347 * this image with a timestamp close to aTime), this method returns true.
349 * Otherwise, this method updates mLastRefreshTime to aTime & returns false.
351 bool HadRecentRefresh(const TimeStamp
& aTime
);
354 * Decides whether animation should or should not be happening,
355 * and makes sure the right thing is being done.
357 virtual void EvaluateAnimation();
360 * Extended by child classes, if they have additional
361 * conditions for being able to animate.
363 virtual bool ShouldAnimate() {
364 return mAnimationConsumers
> 0 && mAnimationMode
!= kDontAnimMode
;
367 virtual nsresult
StartAnimation() = 0;
368 virtual nsresult
StopAnimation() = 0;
370 void SendOnUnlockedDraw(uint32_t aFlags
);
373 // Records the image drawing for startup performance testing.
374 void NotifyDrawingObservers();
377 // Member data shared by all implementations of this abstract class
378 RefPtr
<ProgressTracker
> mProgressTracker
;
379 nsCOMPtr
<nsIURI
> mURI
;
380 TimeStamp mLastRefreshTime
;
381 uint64_t mInnerWindowId
;
382 uint32_t mAnimationConsumers
;
383 uint16_t mAnimationMode
; // Enum values in imgIContainer
384 bool mInitialized
: 1; // Have we been initialized?
385 bool mAnimating
: 1; // Are we currently animating?
386 bool mError
: 1; // Error handling
388 class MOZ_RAII AutoProfilerImagePaintMarker
{
390 explicit AutoProfilerImagePaintMarker(ImageResource
* self
) {
391 if (self
->mURI
&& profiler_thread_is_being_profiled_for_markers()) {
392 mStartTime
= TimeStamp::Now();
393 static const size_t sMaxTruncatedLength
= 1024;
394 mSpec
= nsContentUtils::TruncatedURLForDisplay(self
->mURI
,
395 sMaxTruncatedLength
);
399 ~AutoProfilerImagePaintMarker() {
400 if (!mSpec
.IsEmpty()) {
401 PROFILER_MARKER_TEXT("Image Paint", GRAPHICS
,
402 MarkerTiming::IntervalUntilNowFrom(mStartTime
),
408 TimeStamp mStartTime
;
413 ImageProviderId mProviderId
;
417 } // namespace mozilla
419 #endif // mozilla_image_Image_h