Bug 1610357 [wpt PR 21278] - Update wpt metadata, a=testonly
[gecko.git] / image / Image.h
blob2f2749d015a2416600070e19bc1efac0f0dfb4bf
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/Maybe.h"
10 #include "mozilla/MemoryReporting.h"
11 #include "mozilla/Tuple.h"
12 #include "mozilla/TimeStamp.h"
13 #include "gfx2DGlue.h"
14 #include "imgIContainer.h"
15 #include "ImageContainer.h"
16 #include "LookupResult.h"
17 #include "nsStringFwd.h"
18 #include "ProgressTracker.h"
19 #include "SurfaceCache.h"
21 class imgRequest;
22 class nsIRequest;
23 class nsIInputStream;
25 namespace mozilla {
26 namespace image {
28 class Image;
30 ///////////////////////////////////////////////////////////////////////////////
31 // Memory Reporting
32 ///////////////////////////////////////////////////////////////////////////////
34 struct MemoryCounter {
35 MemoryCounter()
36 : mSource(0),
37 mDecodedHeap(0),
38 mDecodedNonHeap(0),
39 mExternalHandles(0),
40 mFrameIndex(0),
41 mExternalId(0) {}
43 void SetSource(size_t aCount) { mSource = aCount; }
44 size_t Source() const { return mSource; }
45 void SetDecodedHeap(size_t aCount) { mDecodedHeap = aCount; }
46 size_t DecodedHeap() const { return mDecodedHeap; }
47 void SetDecodedNonHeap(size_t aCount) { mDecodedNonHeap = aCount; }
48 size_t DecodedNonHeap() const { return mDecodedNonHeap; }
49 void SetExternalHandles(size_t aCount) { mExternalHandles = aCount; }
50 size_t ExternalHandles() const { return mExternalHandles; }
51 void SetFrameIndex(size_t aIndex) { mFrameIndex = aIndex; }
52 size_t FrameIndex() const { return mFrameIndex; }
53 void SetExternalId(uint64_t aId) { mExternalId = aId; }
54 uint64_t ExternalId() const { return mExternalId; }
56 MemoryCounter& operator+=(const MemoryCounter& aOther) {
57 mSource += aOther.mSource;
58 mDecodedHeap += aOther.mDecodedHeap;
59 mDecodedNonHeap += aOther.mDecodedNonHeap;
60 mExternalHandles += aOther.mExternalHandles;
61 return *this;
64 private:
65 size_t mSource;
66 size_t mDecodedHeap;
67 size_t mDecodedNonHeap;
68 size_t mExternalHandles;
69 size_t mFrameIndex;
70 uint64_t mExternalId;
73 enum class SurfaceMemoryCounterType { NORMAL, COMPOSITING, COMPOSITING_PREV };
75 struct SurfaceMemoryCounter {
76 SurfaceMemoryCounter(
77 const SurfaceKey& aKey, bool aIsLocked, bool aCannotSubstitute,
78 bool aIsFactor2, bool aFinished,
79 SurfaceMemoryCounterType aType = SurfaceMemoryCounterType::NORMAL)
80 : mKey(aKey),
81 mType(aType),
82 mIsLocked(aIsLocked),
83 mCannotSubstitute(aCannotSubstitute),
84 mIsFactor2(aIsFactor2),
85 mFinished(aFinished) {}
87 const SurfaceKey& Key() const { return mKey; }
88 MemoryCounter& Values() { return mValues; }
89 const MemoryCounter& Values() const { return mValues; }
90 SurfaceMemoryCounterType Type() const { return mType; }
91 bool IsLocked() const { return mIsLocked; }
92 bool CannotSubstitute() const { return mCannotSubstitute; }
93 bool IsFactor2() const { return mIsFactor2; }
94 bool IsFinished() const { return mFinished; }
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 const bool mFinished;
106 struct ImageMemoryCounter {
107 ImageMemoryCounter(imgRequest* aRequest, SizeOfState& aState, bool aIsUsed);
108 ImageMemoryCounter(imgRequest* aRequest, Image* aImage, SizeOfState& aState,
109 bool aIsUsed);
111 nsCString& URI() { return mURI; }
112 const nsCString& URI() const { return mURI; }
113 const nsTArray<SurfaceMemoryCounter>& Surfaces() const { return mSurfaces; }
114 const gfx::IntSize IntrinsicSize() const { return mIntrinsicSize; }
115 const MemoryCounter& Values() const { return mValues; }
116 uint32_t Progress() const { return mProgress; }
117 uint16_t Type() const { return mType; }
118 bool IsUsed() const { return mIsUsed; }
119 bool HasError() const { return mHasError; }
120 bool IsValidating() const { return mValidating; }
122 bool IsNotable() const {
123 // Errors or requests without images are always notable.
124 if (mHasError || mProgress == UINT32_MAX || mProgress & FLAG_HAS_ERROR ||
125 mType == imgIContainer::TYPE_REQUEST) {
126 return true;
129 // Sufficiently large images are notable.
130 const size_t NotableThreshold = 16 * 1024;
131 size_t total =
132 mValues.Source() + mValues.DecodedHeap() + mValues.DecodedNonHeap();
133 if (total >= NotableThreshold) {
134 return true;
137 // Incomplete images are always notable as well; the odds of capturing
138 // mid-decode should be fairly low.
139 for (const auto& surface : mSurfaces) {
140 if (!surface.IsFinished()) {
141 return true;
145 return false;
148 private:
149 nsCString mURI;
150 nsTArray<SurfaceMemoryCounter> mSurfaces;
151 gfx::IntSize mIntrinsicSize;
152 MemoryCounter mValues;
153 uint32_t mProgress;
154 uint16_t mType;
155 const bool mIsUsed;
156 bool mHasError;
157 bool mValidating;
160 ///////////////////////////////////////////////////////////////////////////////
161 // Image Base Types
162 ///////////////////////////////////////////////////////////////////////////////
164 class Image : public imgIContainer {
165 public:
167 * Flags for Image initialization.
169 * Meanings:
171 * INIT_FLAG_NONE: Lack of flags
173 * INIT_FLAG_DISCARDABLE: The container should be discardable
175 * INIT_FLAG_DECODE_IMMEDIATELY: The container should decode as soon as
176 * possible, regardless of what our heuristics say.
178 * INIT_FLAG_TRANSIENT: The container is likely to exist for only a short time
179 * before being destroyed. (For example, containers for
180 * multipart/x-mixed-replace image parts fall into this category.) If this
181 * flag is set, INIT_FLAG_DISCARDABLE and INIT_FLAG_DECODE_ONLY_ON_DRAW must
182 * not be set.
184 * INIT_FLAG_SYNC_LOAD: The container is being loaded synchronously, so
185 * it should avoid relying on async workers to get the container ready.
187 static const uint32_t INIT_FLAG_NONE = 0x0;
188 static const uint32_t INIT_FLAG_DISCARDABLE = 0x1;
189 static const uint32_t INIT_FLAG_DECODE_IMMEDIATELY = 0x2;
190 static const uint32_t INIT_FLAG_TRANSIENT = 0x4;
191 static const uint32_t INIT_FLAG_SYNC_LOAD = 0x8;
193 virtual already_AddRefed<ProgressTracker> GetProgressTracker() = 0;
194 virtual void SetProgressTracker(ProgressTracker* aProgressTracker) {}
197 * The size, in bytes, occupied by the compressed source data of the image.
198 * If MallocSizeOf does not work on this platform, uses a fallback approach to
199 * ensure that something reasonable is always returned.
201 virtual size_t SizeOfSourceWithComputedFallback(
202 SizeOfState& aState) const = 0;
205 * Collect an accounting of the memory occupied by the image's surfaces (which
206 * together make up its decoded data). Each surface is recorded as a separate
207 * SurfaceMemoryCounter, stored in @aCounters.
209 virtual void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters,
210 MallocSizeOf aMallocSizeOf) const = 0;
212 virtual void IncrementAnimationConsumers() = 0;
213 virtual void DecrementAnimationConsumers() = 0;
214 #ifdef DEBUG
215 virtual uint32_t GetAnimationConsumers() = 0;
216 #endif
219 * Called from OnDataAvailable when the stream associated with the image has
220 * received new image data. The arguments are the same as OnDataAvailable's,
221 * but by separating this functionality into a different method we don't
222 * interfere with subclasses which wish to implement nsIStreamListener.
224 * Images should not do anything that could send out notifications until they
225 * have received their first OnImageDataAvailable notification; in
226 * particular, this means that instantiating decoders should be deferred
227 * until OnImageDataAvailable is called.
229 virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
230 nsISupports* aContext,
231 nsIInputStream* aInStr,
232 uint64_t aSourceOffset,
233 uint32_t aCount) = 0;
236 * Called from OnStopRequest when the image's underlying request completes.
238 * @param aRequest The completed request.
239 * @param aContext Context from Necko's OnStopRequest.
240 * @param aStatus A success or failure code.
241 * @param aLastPart Whether this is the final part of the underlying request.
243 virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
244 nsISupports* aContext, nsresult aStatus,
245 bool aLastPart) = 0;
248 * Called when the SurfaceCache discards a surface belonging to this image.
250 virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) = 0;
252 virtual void SetInnerWindowID(uint64_t aInnerWindowId) = 0;
253 virtual uint64_t InnerWindowID() const = 0;
255 virtual bool HasError() = 0;
256 virtual void SetHasError() = 0;
258 virtual nsIURI* GetURI() const = 0;
261 class ImageResource : public Image {
262 public:
263 already_AddRefed<ProgressTracker> GetProgressTracker() override {
264 RefPtr<ProgressTracker> progressTracker = mProgressTracker;
265 MOZ_ASSERT(progressTracker);
266 return progressTracker.forget();
269 void SetProgressTracker(ProgressTracker* aProgressTracker) final {
270 MOZ_ASSERT(aProgressTracker);
271 MOZ_ASSERT(!mProgressTracker);
272 mProgressTracker = aProgressTracker;
275 virtual void IncrementAnimationConsumers() override;
276 virtual void DecrementAnimationConsumers() override;
277 #ifdef DEBUG
278 virtual uint32_t GetAnimationConsumers() override {
279 return mAnimationConsumers;
281 #endif
283 virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) override {}
285 virtual void SetInnerWindowID(uint64_t aInnerWindowId) override {
286 mInnerWindowId = aInnerWindowId;
288 virtual uint64_t InnerWindowID() const override { return mInnerWindowId; }
290 virtual bool HasError() override { return mError; }
291 virtual void SetHasError() override { mError = true; }
294 * Returns a non-AddRefed pointer to the URI associated with this image.
295 * Illegal to use off-main-thread.
297 nsIURI* GetURI() const override { return mURI; }
299 protected:
300 explicit ImageResource(nsIURI* aURI);
301 ~ImageResource();
303 layers::ContainerProducerID GetImageProducerId() const {
304 return mImageProducerID;
307 bool GetSpecTruncatedTo1k(nsCString& aSpec) const;
309 // Shared functionality for implementors of imgIContainer. Every
310 // implementation of attribute animationMode should forward here.
311 nsresult GetAnimationModeInternal(uint16_t* aAnimationMode);
312 nsresult SetAnimationModeInternal(uint16_t aAnimationMode);
315 * Helper for RequestRefresh.
317 * If we've had a "recent" refresh (i.e. if this image is being used in
318 * multiple documents & some other document *just* called RequestRefresh() on
319 * this image with a timestamp close to aTime), this method returns true.
321 * Otherwise, this method updates mLastRefreshTime to aTime & returns false.
323 bool HadRecentRefresh(const TimeStamp& aTime);
326 * Decides whether animation should or should not be happening,
327 * and makes sure the right thing is being done.
329 virtual void EvaluateAnimation();
332 * Extended by child classes, if they have additional
333 * conditions for being able to animate.
335 virtual bool ShouldAnimate() {
336 return mAnimationConsumers > 0 && mAnimationMode != kDontAnimMode;
339 virtual nsresult StartAnimation() = 0;
340 virtual nsresult StopAnimation() = 0;
342 void SendOnUnlockedDraw(uint32_t aFlags);
344 #ifdef DEBUG
345 // Records the image drawing for startup performance testing.
346 void NotifyDrawingObservers();
347 #endif
349 // Member data shared by all implementations of this abstract class
350 RefPtr<ProgressTracker> mProgressTracker;
351 nsCOMPtr<nsIURI> mURI;
352 TimeStamp mLastRefreshTime;
353 uint64_t mInnerWindowId;
354 uint32_t mAnimationConsumers;
355 uint16_t mAnimationMode; // Enum values in imgIContainer
356 bool mInitialized : 1; // Have we been initialized?
357 bool mAnimating : 1; // Are we currently animating?
358 bool mError : 1; // Error handling
361 * Attempt to find a matching cached surface in the SurfaceCache, and if not
362 * available, request the production of such a surface (either synchronously
363 * or asynchronously).
365 * If the draw result is BAD_IMAGE, BAD_ARGS or NOT_READY, the size will be
366 * the same as aSize. If it is TEMPORARY_ERROR, INCOMPLETE, or SUCCESS, the
367 * size is a hint as to what we expect the surface size to be, once the best
368 * fitting size is available. It may or may not match the size of the surface
369 * returned at this moment. This is useful for choosing how to store the final
370 * result (e.g. if going into an ImageContainer, ideally we would share the
371 * same container for many requested sizes, if they all end up with the same
372 * best fit size in the end).
374 * A valid surface should only be returned for SUCCESS and INCOMPLETE.
376 * Any other draw result is invalid.
378 virtual Tuple<ImgDrawResult, gfx::IntSize, RefPtr<gfx::SourceSurface>>
379 GetFrameInternal(const gfx::IntSize& aSize,
380 const Maybe<SVGImageContext>& aSVGContext,
381 uint32_t aWhichFrame, uint32_t aFlags) {
382 return MakeTuple(ImgDrawResult::BAD_IMAGE, aSize,
383 RefPtr<gfx::SourceSurface>());
387 * Calculate the estimated size to use for an image container with the given
388 * parameters. It may not be the same as the given size, and it may not be
389 * the same as the size of the surface in the image container, but it is the
390 * best effort estimate.
392 virtual Tuple<ImgDrawResult, gfx::IntSize> GetImageContainerSize(
393 layers::LayerManager* aManager, const gfx::IntSize& aSize,
394 uint32_t aFlags) {
395 return MakeTuple(ImgDrawResult::NOT_SUPPORTED, gfx::IntSize(0, 0));
398 ImgDrawResult GetImageContainerImpl(layers::LayerManager* aManager,
399 const gfx::IntSize& aSize,
400 const Maybe<SVGImageContext>& aSVGContext,
401 uint32_t aFlags,
402 layers::ImageContainer** aContainer);
405 * Re-requests the appropriate frames for each image container using
406 * GetFrameInternal.
407 * @returns True if any image containers were updated, else false.
409 bool UpdateImageContainer(const Maybe<gfx::IntRect>& aDirtyRect);
411 void ReleaseImageContainer();
413 private:
414 void SetCurrentImage(layers::ImageContainer* aContainer,
415 gfx::SourceSurface* aSurface,
416 const Maybe<gfx::IntRect>& aDirtyRect);
418 struct ImageContainerEntry {
419 ImageContainerEntry(const gfx::IntSize& aSize,
420 const Maybe<SVGImageContext>& aSVGContext,
421 layers::ImageContainer* aContainer, uint32_t aFlags)
422 : mSize(aSize),
423 mSVGContext(aSVGContext),
424 mContainer(aContainer),
425 mLastDrawResult(ImgDrawResult::NOT_READY),
426 mFlags(aFlags) {}
428 gfx::IntSize mSize;
429 Maybe<SVGImageContext> mSVGContext;
430 // A weak pointer to our ImageContainer, which stays alive only as long as
431 // the layer system needs it.
432 WeakPtr<layers::ImageContainer> mContainer;
433 // If mContainer is non-null, this contains the ImgDrawResult we obtained
434 // the last time we updated it.
435 ImgDrawResult mLastDrawResult;
436 // Cached flags to use for decoding. FLAG_ASYNC_NOTIFY should always be set
437 // but FLAG_HIGH_QUALITY_SCALING may vary.
438 uint32_t mFlags;
441 AutoTArray<ImageContainerEntry, 1> mImageContainers;
442 layers::ImageContainer::ProducerID mImageProducerID;
443 layers::ImageContainer::FrameID mLastFrameID;
446 } // namespace image
447 } // namespace mozilla
449 #endif // mozilla_image_Image_h