Bug 1654678 Part 2 - Make CUPSPrinter own its CUPS dest data r=nordzilla
[gecko.git] / image / Image.h
blob167f016e9193e8a2373abcd4ab36cf889304e5a1
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 mDecodedUnknown(0),
40 mExternalHandles(0),
41 mFrameIndex(0),
42 mExternalId(0),
43 mSurfaceTypes(0) {}
45 void SetSource(size_t aCount) { mSource = aCount; }
46 size_t Source() const { return mSource; }
47 void SetDecodedHeap(size_t aCount) { mDecodedHeap = aCount; }
48 size_t DecodedHeap() const { return mDecodedHeap; }
49 void SetDecodedNonHeap(size_t aCount) { mDecodedNonHeap = aCount; }
50 size_t DecodedNonHeap() const { return mDecodedNonHeap; }
51 void SetDecodedUnknown(size_t aCount) { mDecodedUnknown = aCount; }
52 size_t DecodedUnknown() const { return mDecodedUnknown; }
53 void SetExternalHandles(size_t aCount) { mExternalHandles = aCount; }
54 size_t ExternalHandles() const { return mExternalHandles; }
55 void SetFrameIndex(size_t aIndex) { mFrameIndex = aIndex; }
56 size_t FrameIndex() const { return mFrameIndex; }
57 void SetExternalId(uint64_t aId) { mExternalId = aId; }
58 uint64_t ExternalId() const { return mExternalId; }
59 void SetSurfaceTypes(uint32_t aTypes) { mSurfaceTypes = aTypes; }
60 uint32_t SurfaceTypes() const { return mSurfaceTypes; }
62 MemoryCounter& operator+=(const MemoryCounter& aOther) {
63 mSource += aOther.mSource;
64 mDecodedHeap += aOther.mDecodedHeap;
65 mDecodedNonHeap += aOther.mDecodedNonHeap;
66 mDecodedUnknown += aOther.mDecodedUnknown;
67 mExternalHandles += aOther.mExternalHandles;
68 mSurfaceTypes |= aOther.mSurfaceTypes;
69 return *this;
72 private:
73 size_t mSource;
74 size_t mDecodedHeap;
75 size_t mDecodedNonHeap;
76 size_t mDecodedUnknown;
77 size_t mExternalHandles;
78 size_t mFrameIndex;
79 uint64_t mExternalId;
80 uint32_t mSurfaceTypes;
83 enum class SurfaceMemoryCounterType { NORMAL, COMPOSITING, COMPOSITING_PREV };
85 struct SurfaceMemoryCounter {
86 SurfaceMemoryCounter(
87 const SurfaceKey& aKey, bool aIsLocked, bool aCannotSubstitute,
88 bool aIsFactor2, bool aFinished,
89 SurfaceMemoryCounterType aType = SurfaceMemoryCounterType::NORMAL)
90 : mKey(aKey),
91 mType(aType),
92 mIsLocked(aIsLocked),
93 mCannotSubstitute(aCannotSubstitute),
94 mIsFactor2(aIsFactor2),
95 mFinished(aFinished) {}
97 const SurfaceKey& Key() const { return mKey; }
98 MemoryCounter& Values() { return mValues; }
99 const MemoryCounter& Values() const { return mValues; }
100 SurfaceMemoryCounterType Type() const { return mType; }
101 bool IsLocked() const { return mIsLocked; }
102 bool CannotSubstitute() const { return mCannotSubstitute; }
103 bool IsFactor2() const { return mIsFactor2; }
104 bool IsFinished() const { return mFinished; }
106 private:
107 const SurfaceKey mKey;
108 MemoryCounter mValues;
109 const SurfaceMemoryCounterType mType;
110 const bool mIsLocked;
111 const bool mCannotSubstitute;
112 const bool mIsFactor2;
113 const bool mFinished;
116 struct ImageMemoryCounter {
117 ImageMemoryCounter(imgRequest* aRequest, SizeOfState& aState, bool aIsUsed);
118 ImageMemoryCounter(imgRequest* aRequest, Image* aImage, SizeOfState& aState,
119 bool aIsUsed);
121 nsCString& URI() { return mURI; }
122 const nsCString& URI() const { return mURI; }
123 const nsTArray<SurfaceMemoryCounter>& Surfaces() const { return mSurfaces; }
124 const gfx::IntSize IntrinsicSize() const { return mIntrinsicSize; }
125 const MemoryCounter& Values() const { return mValues; }
126 uint32_t Progress() const { return mProgress; }
127 uint16_t Type() const { return mType; }
128 bool IsUsed() const { return mIsUsed; }
129 bool HasError() const { return mHasError; }
130 bool IsValidating() const { return mValidating; }
132 bool IsNotable() const {
133 // Errors or requests without images are always notable.
134 if (mHasError || mValidating || mProgress == UINT32_MAX ||
135 mProgress & FLAG_HAS_ERROR || mType == imgIContainer::TYPE_REQUEST) {
136 return true;
139 // Sufficiently large images are notable.
140 const size_t NotableThreshold = 16 * 1024;
141 size_t total = mValues.Source() + mValues.DecodedHeap() +
142 mValues.DecodedNonHeap() + mValues.DecodedUnknown();
143 if (total >= NotableThreshold) {
144 return true;
147 // Incomplete images are always notable as well; the odds of capturing
148 // mid-decode should be fairly low.
149 for (const auto& surface : mSurfaces) {
150 if (!surface.IsFinished()) {
151 return true;
155 return false;
158 private:
159 nsCString mURI;
160 nsTArray<SurfaceMemoryCounter> mSurfaces;
161 gfx::IntSize mIntrinsicSize;
162 MemoryCounter mValues;
163 uint32_t mProgress;
164 uint16_t mType;
165 const bool mIsUsed;
166 bool mHasError;
167 bool mValidating;
170 ///////////////////////////////////////////////////////////////////////////////
171 // Image Base Types
172 ///////////////////////////////////////////////////////////////////////////////
174 class Image : public imgIContainer {
175 public:
177 * Flags for Image initialization.
179 * Meanings:
181 * INIT_FLAG_NONE: Lack of flags
183 * INIT_FLAG_DISCARDABLE: The container should be discardable
185 * INIT_FLAG_DECODE_IMMEDIATELY: The container should decode as soon as
186 * possible, regardless of what our heuristics say.
188 * INIT_FLAG_TRANSIENT: The container is likely to exist for only a short time
189 * before being destroyed. (For example, containers for
190 * multipart/x-mixed-replace image parts fall into this category.) If this
191 * flag is set, INIT_FLAG_DISCARDABLE and INIT_FLAG_DECODE_ONLY_ON_DRAW must
192 * not be set.
194 * INIT_FLAG_SYNC_LOAD: The container is being loaded synchronously, so
195 * it should avoid relying on async workers to get the container ready.
197 static const uint32_t INIT_FLAG_NONE = 0x0;
198 static const uint32_t INIT_FLAG_DISCARDABLE = 0x1;
199 static const uint32_t INIT_FLAG_DECODE_IMMEDIATELY = 0x2;
200 static const uint32_t INIT_FLAG_TRANSIENT = 0x4;
201 static const uint32_t INIT_FLAG_SYNC_LOAD = 0x8;
203 virtual already_AddRefed<ProgressTracker> GetProgressTracker() = 0;
204 virtual void SetProgressTracker(ProgressTracker* aProgressTracker) {}
207 * The size, in bytes, occupied by the compressed source data of the image.
208 * If MallocSizeOf does not work on this platform, uses a fallback approach to
209 * ensure that something reasonable is always returned.
211 virtual size_t SizeOfSourceWithComputedFallback(
212 SizeOfState& aState) const = 0;
215 * Collect an accounting of the memory occupied by the image's surfaces (which
216 * together make up its decoded data). Each surface is recorded as a separate
217 * SurfaceMemoryCounter, stored in @aCounters.
219 virtual void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters,
220 MallocSizeOf aMallocSizeOf) const = 0;
222 virtual void IncrementAnimationConsumers() = 0;
223 virtual void DecrementAnimationConsumers() = 0;
224 #ifdef DEBUG
225 virtual uint32_t GetAnimationConsumers() = 0;
226 #endif
229 * Called from OnDataAvailable when the stream associated with the image has
230 * received new image data. The arguments are the same as OnDataAvailable's,
231 * but by separating this functionality into a different method we don't
232 * interfere with subclasses which wish to implement nsIStreamListener.
234 * Images should not do anything that could send out notifications until they
235 * have received their first OnImageDataAvailable notification; in
236 * particular, this means that instantiating decoders should be deferred
237 * until OnImageDataAvailable is called.
239 virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
240 nsISupports* aContext,
241 nsIInputStream* aInStr,
242 uint64_t aSourceOffset,
243 uint32_t aCount) = 0;
246 * Called from OnStopRequest when the image's underlying request completes.
248 * @param aRequest The completed request.
249 * @param aContext Context from Necko's OnStopRequest.
250 * @param aStatus A success or failure code.
251 * @param aLastPart Whether this is the final part of the underlying request.
253 virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
254 nsISupports* aContext, nsresult aStatus,
255 bool aLastPart) = 0;
258 * Called when the SurfaceCache discards a surface belonging to this image.
260 virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) = 0;
262 virtual void SetInnerWindowID(uint64_t aInnerWindowId) = 0;
263 virtual uint64_t InnerWindowID() const = 0;
265 virtual bool HasError() = 0;
266 virtual void SetHasError() = 0;
268 virtual nsIURI* GetURI() const = 0;
270 NS_IMETHOD GetHotspotX(int32_t* aX) override {
271 *aX = 0;
272 return NS_OK;
274 NS_IMETHOD GetHotspotY(int32_t* aY) override {
275 *aY = 0;
276 return NS_OK;
280 class ImageResource : public Image {
281 public:
282 already_AddRefed<ProgressTracker> GetProgressTracker() override {
283 RefPtr<ProgressTracker> progressTracker = mProgressTracker;
284 MOZ_ASSERT(progressTracker);
285 return progressTracker.forget();
288 void SetProgressTracker(ProgressTracker* aProgressTracker) final {
289 MOZ_ASSERT(aProgressTracker);
290 MOZ_ASSERT(!mProgressTracker);
291 mProgressTracker = aProgressTracker;
294 virtual void IncrementAnimationConsumers() override;
295 virtual void DecrementAnimationConsumers() override;
296 #ifdef DEBUG
297 virtual uint32_t GetAnimationConsumers() override {
298 return mAnimationConsumers;
300 #endif
302 virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) override {}
304 virtual void SetInnerWindowID(uint64_t aInnerWindowId) override {
305 mInnerWindowId = aInnerWindowId;
307 virtual uint64_t InnerWindowID() const override { return mInnerWindowId; }
309 virtual bool HasError() override { return mError; }
310 virtual void SetHasError() override { mError = true; }
313 * Returns a non-AddRefed pointer to the URI associated with this image.
314 * Illegal to use off-main-thread.
316 nsIURI* GetURI() const override { return mURI; }
318 protected:
319 explicit ImageResource(nsIURI* aURI);
320 ~ImageResource();
322 layers::ContainerProducerID GetImageProducerId() const {
323 return mImageProducerID;
326 bool GetSpecTruncatedTo1k(nsCString& aSpec) const;
328 // Shared functionality for implementors of imgIContainer. Every
329 // implementation of attribute animationMode should forward here.
330 nsresult GetAnimationModeInternal(uint16_t* aAnimationMode);
331 nsresult SetAnimationModeInternal(uint16_t aAnimationMode);
334 * Helper for RequestRefresh.
336 * If we've had a "recent" refresh (i.e. if this image is being used in
337 * multiple documents & some other document *just* called RequestRefresh() on
338 * this image with a timestamp close to aTime), this method returns true.
340 * Otherwise, this method updates mLastRefreshTime to aTime & returns false.
342 bool HadRecentRefresh(const TimeStamp& aTime);
345 * Decides whether animation should or should not be happening,
346 * and makes sure the right thing is being done.
348 virtual void EvaluateAnimation();
351 * Extended by child classes, if they have additional
352 * conditions for being able to animate.
354 virtual bool ShouldAnimate() {
355 return mAnimationConsumers > 0 && mAnimationMode != kDontAnimMode;
358 virtual nsresult StartAnimation() = 0;
359 virtual nsresult StopAnimation() = 0;
361 void SendOnUnlockedDraw(uint32_t aFlags);
363 #ifdef DEBUG
364 // Records the image drawing for startup performance testing.
365 void NotifyDrawingObservers();
366 #endif
368 // Member data shared by all implementations of this abstract class
369 RefPtr<ProgressTracker> mProgressTracker;
370 nsCOMPtr<nsIURI> mURI;
371 TimeStamp mLastRefreshTime;
372 uint64_t mInnerWindowId;
373 uint32_t mAnimationConsumers;
374 uint16_t mAnimationMode; // Enum values in imgIContainer
375 bool mInitialized : 1; // Have we been initialized?
376 bool mAnimating : 1; // Are we currently animating?
377 bool mError : 1; // Error handling
380 * Attempt to find a matching cached surface in the SurfaceCache, and if not
381 * available, request the production of such a surface (either synchronously
382 * or asynchronously).
384 * If the draw result is BAD_IMAGE, BAD_ARGS or NOT_READY, the size will be
385 * the same as aSize. If it is TEMPORARY_ERROR, INCOMPLETE, or SUCCESS, the
386 * size is a hint as to what we expect the surface size to be, once the best
387 * fitting size is available. It may or may not match the size of the surface
388 * returned at this moment. This is useful for choosing how to store the final
389 * result (e.g. if going into an ImageContainer, ideally we would share the
390 * same container for many requested sizes, if they all end up with the same
391 * best fit size in the end).
393 * A valid surface should only be returned for SUCCESS and INCOMPLETE.
395 * Any other draw result is invalid.
397 virtual Tuple<ImgDrawResult, gfx::IntSize, RefPtr<gfx::SourceSurface>>
398 GetFrameInternal(const gfx::IntSize& aSize,
399 const Maybe<SVGImageContext>& aSVGContext,
400 uint32_t aWhichFrame, uint32_t aFlags) {
401 return MakeTuple(ImgDrawResult::BAD_IMAGE, aSize,
402 RefPtr<gfx::SourceSurface>());
406 * Calculate the estimated size to use for an image container with the given
407 * parameters. It may not be the same as the given size, and it may not be
408 * the same as the size of the surface in the image container, but it is the
409 * best effort estimate.
411 virtual Tuple<ImgDrawResult, gfx::IntSize> GetImageContainerSize(
412 layers::LayerManager* aManager, const gfx::IntSize& aSize,
413 uint32_t aFlags) {
414 return MakeTuple(ImgDrawResult::NOT_SUPPORTED, gfx::IntSize(0, 0));
417 ImgDrawResult GetImageContainerImpl(layers::LayerManager* aManager,
418 const gfx::IntSize& aSize,
419 const Maybe<SVGImageContext>& aSVGContext,
420 uint32_t aFlags,
421 layers::ImageContainer** aContainer);
424 * Re-requests the appropriate frames for each image container using
425 * GetFrameInternal.
426 * @returns True if any image containers were updated, else false.
428 bool UpdateImageContainer(const Maybe<gfx::IntRect>& aDirtyRect);
430 void ReleaseImageContainer();
432 private:
433 void SetCurrentImage(layers::ImageContainer* aContainer,
434 gfx::SourceSurface* aSurface,
435 const Maybe<gfx::IntRect>& aDirtyRect);
437 struct ImageContainerEntry {
438 ImageContainerEntry(const gfx::IntSize& aSize,
439 const Maybe<SVGImageContext>& aSVGContext,
440 layers::ImageContainer* aContainer, uint32_t aFlags)
441 : mSize(aSize),
442 mSVGContext(aSVGContext),
443 mContainer(aContainer),
444 mLastDrawResult(ImgDrawResult::NOT_READY),
445 mFlags(aFlags) {}
447 gfx::IntSize mSize;
448 Maybe<SVGImageContext> mSVGContext;
449 // A weak pointer to our ImageContainer, which stays alive only as long as
450 // the layer system needs it.
451 WeakPtr<layers::ImageContainer> mContainer;
452 // If mContainer is non-null, this contains the ImgDrawResult we obtained
453 // the last time we updated it.
454 ImgDrawResult mLastDrawResult;
455 // Cached flags to use for decoding. FLAG_ASYNC_NOTIFY should always be set
456 // but FLAG_HIGH_QUALITY_SCALING may vary.
457 uint32_t mFlags;
460 AutoTArray<ImageContainerEntry, 1> mImageContainers;
461 layers::ImageContainer::ProducerID mImageProducerID;
462 layers::ImageContainer::FrameID mLastFrameID;
465 } // namespace image
466 } // namespace mozilla
468 #endif // mozilla_image_Image_h