Bug 1686855 [wpt PR 27197] - PlzDedicatedWorker: WPT for clients.matchAll() with...
[gecko.git] / image / Image.h
blob48fe9a072bd187043552a1b8fe117e18d163ee12
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/SizeOfState.h"
12 #include "mozilla/ThreadSafeWeakPtr.h"
13 #include "mozilla/TimeStamp.h"
14 #include "mozilla/Tuple.h"
15 #include "gfx2DGlue.h"
16 #include "imgIContainer.h"
17 #include "ImageContainer.h"
18 #include "LookupResult.h"
19 #include "nsStringFwd.h"
20 #include "ProgressTracker.h"
21 #include "SurfaceCache.h"
23 class imgRequest;
24 class nsIRequest;
25 class nsIInputStream;
27 namespace mozilla {
28 namespace image {
30 class Image;
32 ///////////////////////////////////////////////////////////////////////////////
33 // Memory Reporting
34 ///////////////////////////////////////////////////////////////////////////////
36 struct MemoryCounter {
37 MemoryCounter()
38 : mSource(0),
39 mDecodedHeap(0),
40 mDecodedNonHeap(0),
41 mDecodedUnknown(0),
42 mExternalHandles(0),
43 mFrameIndex(0),
44 mExternalId(0),
45 mSurfaceTypes(0) {}
47 void SetSource(size_t aCount) { mSource = aCount; }
48 size_t Source() const { return mSource; }
49 void SetDecodedHeap(size_t aCount) { mDecodedHeap = aCount; }
50 size_t DecodedHeap() const { return mDecodedHeap; }
51 void SetDecodedNonHeap(size_t aCount) { mDecodedNonHeap = aCount; }
52 size_t DecodedNonHeap() const { return mDecodedNonHeap; }
53 void SetDecodedUnknown(size_t aCount) { mDecodedUnknown = aCount; }
54 size_t DecodedUnknown() const { return mDecodedUnknown; }
55 void SetExternalHandles(size_t aCount) { mExternalHandles = aCount; }
56 size_t ExternalHandles() const { return mExternalHandles; }
57 void SetFrameIndex(size_t aIndex) { mFrameIndex = aIndex; }
58 size_t FrameIndex() const { return mFrameIndex; }
59 void SetExternalId(uint64_t aId) { mExternalId = aId; }
60 uint64_t ExternalId() const { return mExternalId; }
61 void SetSurfaceTypes(uint32_t aTypes) { mSurfaceTypes = aTypes; }
62 uint32_t SurfaceTypes() const { return mSurfaceTypes; }
64 MemoryCounter& operator+=(const MemoryCounter& aOther) {
65 mSource += aOther.mSource;
66 mDecodedHeap += aOther.mDecodedHeap;
67 mDecodedNonHeap += aOther.mDecodedNonHeap;
68 mDecodedUnknown += aOther.mDecodedUnknown;
69 mExternalHandles += aOther.mExternalHandles;
70 mSurfaceTypes |= aOther.mSurfaceTypes;
71 return *this;
74 private:
75 size_t mSource;
76 size_t mDecodedHeap;
77 size_t mDecodedNonHeap;
78 size_t mDecodedUnknown;
79 size_t mExternalHandles;
80 size_t mFrameIndex;
81 uint64_t mExternalId;
82 uint32_t mSurfaceTypes;
85 enum class SurfaceMemoryCounterType { NORMAL, COMPOSITING, COMPOSITING_PREV };
87 struct SurfaceMemoryCounter {
88 SurfaceMemoryCounter(
89 const SurfaceKey& aKey, bool aIsLocked, bool aCannotSubstitute,
90 bool aIsFactor2, bool aFinished,
91 SurfaceMemoryCounterType aType = SurfaceMemoryCounterType::NORMAL)
92 : mKey(aKey),
93 mType(aType),
94 mIsLocked(aIsLocked),
95 mCannotSubstitute(aCannotSubstitute),
96 mIsFactor2(aIsFactor2),
97 mFinished(aFinished) {}
99 const SurfaceKey& Key() const { return mKey; }
100 MemoryCounter& Values() { return mValues; }
101 const MemoryCounter& Values() const { return mValues; }
102 SurfaceMemoryCounterType Type() const { return mType; }
103 bool IsLocked() const { return mIsLocked; }
104 bool CannotSubstitute() const { return mCannotSubstitute; }
105 bool IsFactor2() const { return mIsFactor2; }
106 bool IsFinished() const { return mFinished; }
108 private:
109 const SurfaceKey mKey;
110 MemoryCounter mValues;
111 const SurfaceMemoryCounterType mType;
112 const bool mIsLocked;
113 const bool mCannotSubstitute;
114 const bool mIsFactor2;
115 const bool mFinished;
118 struct ImageMemoryCounter {
119 ImageMemoryCounter(imgRequest* aRequest, SizeOfState& aState, bool aIsUsed);
120 ImageMemoryCounter(imgRequest* aRequest, Image* aImage, SizeOfState& aState,
121 bool aIsUsed);
123 nsCString& URI() { return mURI; }
124 const nsCString& URI() const { return mURI; }
125 const nsTArray<SurfaceMemoryCounter>& Surfaces() const { return mSurfaces; }
126 const gfx::IntSize IntrinsicSize() const { return mIntrinsicSize; }
127 const MemoryCounter& Values() const { return mValues; }
128 uint32_t Progress() const { return mProgress; }
129 uint16_t Type() const { return mType; }
130 bool IsUsed() const { return mIsUsed; }
131 bool HasError() const { return mHasError; }
132 bool IsValidating() const { return mValidating; }
134 bool IsNotable() const {
135 // Errors or requests without images are always notable.
136 if (mHasError || mValidating || mProgress == UINT32_MAX ||
137 mProgress & FLAG_HAS_ERROR || mType == imgIContainer::TYPE_REQUEST) {
138 return true;
141 // Sufficiently large images are notable.
142 const size_t NotableThreshold = 16 * 1024;
143 size_t total = mValues.Source() + mValues.DecodedHeap() +
144 mValues.DecodedNonHeap() + mValues.DecodedUnknown();
145 if (total >= NotableThreshold) {
146 return true;
149 // Incomplete images are always notable as well; the odds of capturing
150 // mid-decode should be fairly low.
151 for (const auto& surface : mSurfaces) {
152 if (!surface.IsFinished()) {
153 return true;
157 return false;
160 private:
161 nsCString mURI;
162 nsTArray<SurfaceMemoryCounter> mSurfaces;
163 gfx::IntSize mIntrinsicSize;
164 MemoryCounter mValues;
165 uint32_t mProgress;
166 uint16_t mType;
167 const bool mIsUsed;
168 bool mHasError;
169 bool mValidating;
172 ///////////////////////////////////////////////////////////////////////////////
173 // Image Base Types
174 ///////////////////////////////////////////////////////////////////////////////
176 class Image : public imgIContainer {
177 public:
179 * Flags for Image initialization.
181 * Meanings:
183 * INIT_FLAG_NONE: Lack of flags
185 * INIT_FLAG_DISCARDABLE: The container should be discardable
187 * INIT_FLAG_DECODE_IMMEDIATELY: The container should decode as soon as
188 * possible, regardless of what our heuristics say.
190 * INIT_FLAG_TRANSIENT: The container is likely to exist for only a short time
191 * before being destroyed. (For example, containers for
192 * multipart/x-mixed-replace image parts fall into this category.) If this
193 * flag is set, INIT_FLAG_DISCARDABLE and INIT_FLAG_DECODE_ONLY_ON_DRAW must
194 * not be set.
196 * INIT_FLAG_SYNC_LOAD: The container is being loaded synchronously, so
197 * it should avoid relying on async workers to get the container ready.
199 static const uint32_t INIT_FLAG_NONE = 0x0;
200 static const uint32_t INIT_FLAG_DISCARDABLE = 0x1;
201 static const uint32_t INIT_FLAG_DECODE_IMMEDIATELY = 0x2;
202 static const uint32_t INIT_FLAG_TRANSIENT = 0x4;
203 static const uint32_t INIT_FLAG_SYNC_LOAD = 0x8;
205 virtual already_AddRefed<ProgressTracker> GetProgressTracker() = 0;
206 virtual void SetProgressTracker(ProgressTracker* aProgressTracker) {}
209 * The size, in bytes, occupied by the compressed source data of the image.
210 * If MallocSizeOf does not work on this platform, uses a fallback approach to
211 * ensure that something reasonable is always returned.
213 virtual size_t SizeOfSourceWithComputedFallback(
214 SizeOfState& aState) const = 0;
217 * Collect an accounting of the memory occupied by the image's surfaces (which
218 * together make up its decoded data). Each surface is recorded as a separate
219 * SurfaceMemoryCounter, stored in @aCounters.
221 virtual void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters,
222 MallocSizeOf aMallocSizeOf) const = 0;
224 virtual void IncrementAnimationConsumers() = 0;
225 virtual void DecrementAnimationConsumers() = 0;
226 #ifdef DEBUG
227 virtual uint32_t GetAnimationConsumers() = 0;
228 #endif
231 * Called from OnDataAvailable when the stream associated with the image has
232 * received new image data. The arguments are the same as OnDataAvailable's,
233 * but by separating this functionality into a different method we don't
234 * interfere with subclasses which wish to implement nsIStreamListener.
236 * Images should not do anything that could send out notifications until they
237 * have received their first OnImageDataAvailable notification; in
238 * particular, this means that instantiating decoders should be deferred
239 * until OnImageDataAvailable is called.
241 virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
242 nsISupports* aContext,
243 nsIInputStream* aInStr,
244 uint64_t aSourceOffset,
245 uint32_t aCount) = 0;
248 * Called from OnStopRequest when the image's underlying request completes.
250 * @param aRequest The completed request.
251 * @param aContext Context from Necko's OnStopRequest.
252 * @param aStatus A success or failure code.
253 * @param aLastPart Whether this is the final part of the underlying request.
255 virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
256 nsISupports* aContext, nsresult aStatus,
257 bool aLastPart) = 0;
260 * Called when the SurfaceCache discards a surface belonging to this image.
262 virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) = 0;
264 virtual void SetInnerWindowID(uint64_t aInnerWindowId) = 0;
265 virtual uint64_t InnerWindowID() const = 0;
267 virtual bool HasError() = 0;
268 virtual void SetHasError() = 0;
270 virtual nsIURI* GetURI() const = 0;
272 NS_IMETHOD GetHotspotX(int32_t* aX) override {
273 *aX = 0;
274 return NS_OK;
276 NS_IMETHOD GetHotspotY(int32_t* aY) override {
277 *aY = 0;
278 return NS_OK;
282 class ImageResource : public Image {
283 public:
284 already_AddRefed<ProgressTracker> GetProgressTracker() override {
285 RefPtr<ProgressTracker> progressTracker = mProgressTracker;
286 MOZ_ASSERT(progressTracker);
287 return progressTracker.forget();
290 void SetProgressTracker(ProgressTracker* aProgressTracker) final {
291 MOZ_ASSERT(aProgressTracker);
292 MOZ_ASSERT(!mProgressTracker);
293 mProgressTracker = aProgressTracker;
296 virtual void IncrementAnimationConsumers() override;
297 virtual void DecrementAnimationConsumers() override;
298 #ifdef DEBUG
299 virtual uint32_t GetAnimationConsumers() override {
300 return mAnimationConsumers;
302 #endif
304 virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) override {}
306 virtual void SetInnerWindowID(uint64_t aInnerWindowId) override {
307 mInnerWindowId = aInnerWindowId;
309 virtual uint64_t InnerWindowID() const override { return mInnerWindowId; }
311 virtual bool HasError() override { return mError; }
312 virtual void SetHasError() override { mError = true; }
315 * Returns a non-AddRefed pointer to the URI associated with this image.
316 * Illegal to use off-main-thread.
318 nsIURI* GetURI() const override { return mURI; }
320 protected:
321 explicit ImageResource(nsIURI* aURI);
322 ~ImageResource();
324 layers::ContainerProducerID GetImageProducerId() const {
325 return mImageProducerID;
328 bool GetSpecTruncatedTo1k(nsCString& aSpec) const;
330 // Shared functionality for implementors of imgIContainer. Every
331 // implementation of attribute animationMode should forward here.
332 nsresult GetAnimationModeInternal(uint16_t* aAnimationMode);
333 nsresult SetAnimationModeInternal(uint16_t aAnimationMode);
336 * Helper for RequestRefresh.
338 * If we've had a "recent" refresh (i.e. if this image is being used in
339 * multiple documents & some other document *just* called RequestRefresh() on
340 * this image with a timestamp close to aTime), this method returns true.
342 * Otherwise, this method updates mLastRefreshTime to aTime & returns false.
344 bool HadRecentRefresh(const TimeStamp& aTime);
347 * Decides whether animation should or should not be happening,
348 * and makes sure the right thing is being done.
350 virtual void EvaluateAnimation();
353 * Extended by child classes, if they have additional
354 * conditions for being able to animate.
356 virtual bool ShouldAnimate() {
357 return mAnimationConsumers > 0 && mAnimationMode != kDontAnimMode;
360 virtual nsresult StartAnimation() = 0;
361 virtual nsresult StopAnimation() = 0;
363 void SendOnUnlockedDraw(uint32_t aFlags);
365 #ifdef DEBUG
366 // Records the image drawing for startup performance testing.
367 void NotifyDrawingObservers();
368 #endif
370 // Member data shared by all implementations of this abstract class
371 RefPtr<ProgressTracker> mProgressTracker;
372 nsCOMPtr<nsIURI> mURI;
373 TimeStamp mLastRefreshTime;
374 uint64_t mInnerWindowId;
375 uint32_t mAnimationConsumers;
376 uint16_t mAnimationMode; // Enum values in imgIContainer
377 bool mInitialized : 1; // Have we been initialized?
378 bool mAnimating : 1; // Are we currently animating?
379 bool mError : 1; // Error handling
382 * Attempt to find a matching cached surface in the SurfaceCache, and if not
383 * available, request the production of such a surface (either synchronously
384 * or asynchronously).
386 * If the draw result is BAD_IMAGE, BAD_ARGS or NOT_READY, the size will be
387 * the same as aSize. If it is TEMPORARY_ERROR, INCOMPLETE, or SUCCESS, the
388 * size is a hint as to what we expect the surface size to be, once the best
389 * fitting size is available. It may or may not match the size of the surface
390 * returned at this moment. This is useful for choosing how to store the final
391 * result (e.g. if going into an ImageContainer, ideally we would share the
392 * same container for many requested sizes, if they all end up with the same
393 * best fit size in the end).
395 * A valid surface should only be returned for SUCCESS and INCOMPLETE.
397 * Any other draw result is invalid.
399 virtual Tuple<ImgDrawResult, gfx::IntSize, RefPtr<gfx::SourceSurface>>
400 GetFrameInternal(const gfx::IntSize& aSize,
401 const Maybe<SVGImageContext>& aSVGContext,
402 uint32_t aWhichFrame, uint32_t aFlags) {
403 return MakeTuple(ImgDrawResult::BAD_IMAGE, aSize,
404 RefPtr<gfx::SourceSurface>());
408 * Calculate the estimated size to use for an image container with the given
409 * parameters. It may not be the same as the given size, and it may not be
410 * the same as the size of the surface in the image container, but it is the
411 * best effort estimate.
413 virtual Tuple<ImgDrawResult, gfx::IntSize> GetImageContainerSize(
414 layers::LayerManager* aManager, const gfx::IntSize& aSize,
415 uint32_t aFlags) {
416 return MakeTuple(ImgDrawResult::NOT_SUPPORTED, gfx::IntSize(0, 0));
419 ImgDrawResult GetImageContainerImpl(layers::LayerManager* aManager,
420 const gfx::IntSize& aSize,
421 const Maybe<SVGImageContext>& aSVGContext,
422 uint32_t aFlags,
423 layers::ImageContainer** aContainer);
426 * Re-requests the appropriate frames for each image container using
427 * GetFrameInternal.
428 * @returns True if any image containers were updated, else false.
430 bool UpdateImageContainer(const Maybe<gfx::IntRect>& aDirtyRect);
432 void ReleaseImageContainer();
434 private:
435 void SetCurrentImage(layers::ImageContainer* aContainer,
436 gfx::SourceSurface* aSurface,
437 const Maybe<gfx::IntRect>& aDirtyRect);
439 struct ImageContainerEntry {
440 ImageContainerEntry(const gfx::IntSize& aSize,
441 const Maybe<SVGImageContext>& aSVGContext,
442 layers::ImageContainer* aContainer, uint32_t aFlags)
443 : mSize(aSize),
444 mSVGContext(aSVGContext),
445 mContainer(aContainer),
446 mLastDrawResult(ImgDrawResult::NOT_READY),
447 mFlags(aFlags) {}
449 gfx::IntSize mSize;
450 Maybe<SVGImageContext> mSVGContext;
451 // A weak pointer to our ImageContainer, which stays alive only as long as
452 // the layer system needs it.
453 ThreadSafeWeakPtr<layers::ImageContainer> mContainer;
454 // If mContainer is non-null, this contains the ImgDrawResult we obtained
455 // the last time we updated it.
456 ImgDrawResult mLastDrawResult;
457 // Cached flags to use for decoding. FLAG_ASYNC_NOTIFY should always be set
458 // but FLAG_HIGH_QUALITY_SCALING may vary.
459 uint32_t mFlags;
462 AutoTArray<ImageContainerEntry, 1> mImageContainers;
463 layers::ImageContainer::ProducerID mImageProducerID;
464 layers::ImageContainer::FrameID mLastFrameID;
467 } // namespace image
468 } // namespace mozilla
470 #endif // mozilla_image_Image_h