Line data Source code
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/Tuple.h"
11 : #include "mozilla/TimeStamp.h"
12 : #include "gfx2DGlue.h"
13 : #include "imgIContainer.h"
14 : #include "ImageContainer.h"
15 : #include "LookupResult.h"
16 : #include "nsStringFwd.h"
17 : #include "ProgressTracker.h"
18 : #include "SurfaceCache.h"
19 :
20 : class nsIRequest;
21 : class nsIInputStream;
22 :
23 : namespace mozilla {
24 : namespace image {
25 :
26 : class Image;
27 :
28 : ///////////////////////////////////////////////////////////////////////////////
29 : // Memory Reporting
30 : ///////////////////////////////////////////////////////////////////////////////
31 :
32 : struct MemoryCounter
33 : {
34 : MemoryCounter()
35 0 : : mSource(0)
36 : , mDecodedHeap(0)
37 : , mDecodedNonHeap(0)
38 0 : , mExternalHandles(0)
39 : { }
40 :
41 0 : void SetSource(size_t aCount) { mSource = aCount; }
42 : size_t Source() const { return mSource; }
43 0 : void SetDecodedHeap(size_t aCount) { mDecodedHeap = aCount; }
44 : size_t DecodedHeap() const { return mDecodedHeap; }
45 0 : void SetDecodedNonHeap(size_t aCount) { mDecodedNonHeap = aCount; }
46 : size_t DecodedNonHeap() const { return mDecodedNonHeap; }
47 0 : void SetExternalHandles(size_t aCount) { mExternalHandles = aCount; }
48 : size_t ExternalHandles() const { return mExternalHandles; }
49 :
50 0 : MemoryCounter& operator+=(const MemoryCounter& aOther)
51 : {
52 0 : mSource += aOther.mSource;
53 0 : mDecodedHeap += aOther.mDecodedHeap;
54 0 : mDecodedNonHeap += aOther.mDecodedNonHeap;
55 0 : mExternalHandles += aOther.mExternalHandles;
56 0 : return *this;
57 : }
58 :
59 : private:
60 : size_t mSource;
61 : size_t mDecodedHeap;
62 : size_t mDecodedNonHeap;
63 : size_t mExternalHandles;
64 : };
65 :
66 : enum class SurfaceMemoryCounterType
67 : {
68 : NORMAL,
69 : COMPOSITING,
70 : COMPOSITING_PREV
71 : };
72 :
73 0 : struct SurfaceMemoryCounter
74 : {
75 : SurfaceMemoryCounter(const SurfaceKey& aKey,
76 : bool aIsLocked,
77 : bool aCannotSubstitute,
78 : bool aIsFactor2,
79 : SurfaceMemoryCounterType aType =
80 : SurfaceMemoryCounterType::NORMAL)
81 0 : : mKey(aKey)
82 : , mType(aType)
83 : , mIsLocked(aIsLocked)
84 : , mCannotSubstitute(aCannotSubstitute)
85 0 : , mIsFactor2(aIsFactor2)
86 : { }
87 :
88 : const SurfaceKey& Key() const { return mKey; }
89 : MemoryCounter& Values() { return mValues; }
90 0 : const MemoryCounter& Values() const { return mValues; }
91 : SurfaceMemoryCounterType Type() const { return mType; }
92 : bool IsLocked() const { return mIsLocked; }
93 : bool CannotSubstitute() const { return mCannotSubstitute; }
94 : bool IsFactor2() const { return mIsFactor2; }
95 :
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 : };
104 :
105 0 : struct ImageMemoryCounter
106 : {
107 : ImageMemoryCounter(Image* aImage, SizeOfState& aState, bool aIsUsed);
108 :
109 0 : nsCString& URI() { return mURI; }
110 : const nsCString& URI() const { return mURI; }
111 : const nsTArray<SurfaceMemoryCounter>& Surfaces() const { return mSurfaces; }
112 0 : const gfx::IntSize IntrinsicSize() const { return mIntrinsicSize; }
113 0 : const MemoryCounter& Values() const { return mValues; }
114 : uint16_t Type() const { return mType; }
115 : bool IsUsed() const { return mIsUsed; }
116 :
117 0 : bool IsNotable() const
118 : {
119 0 : const size_t NotableThreshold = 16 * 1024;
120 0 : size_t total = mValues.Source() + mValues.DecodedHeap()
121 0 : + mValues.DecodedNonHeap();
122 0 : return total >= NotableThreshold;
123 : }
124 :
125 : private:
126 : nsCString mURI;
127 : nsTArray<SurfaceMemoryCounter> mSurfaces;
128 : gfx::IntSize mIntrinsicSize;
129 : MemoryCounter mValues;
130 : uint16_t mType;
131 : const bool mIsUsed;
132 : };
133 :
134 :
135 : ///////////////////////////////////////////////////////////////////////////////
136 : // Image Base Types
137 : ///////////////////////////////////////////////////////////////////////////////
138 :
139 40 : class Image : public imgIContainer
140 : {
141 : public:
142 : /**
143 : * Flags for Image initialization.
144 : *
145 : * Meanings:
146 : *
147 : * INIT_FLAG_NONE: Lack of flags
148 : *
149 : * INIT_FLAG_DISCARDABLE: The container should be discardable
150 : *
151 : * INIT_FLAG_DECODE_IMMEDIATELY: The container should decode as soon as
152 : * possible, regardless of what our heuristics say.
153 : *
154 : * INIT_FLAG_TRANSIENT: The container is likely to exist for only a short time
155 : * before being destroyed. (For example, containers for
156 : * multipart/x-mixed-replace image parts fall into this category.) If this
157 : * flag is set, INIT_FLAG_DISCARDABLE and INIT_FLAG_DECODE_ONLY_ON_DRAW must
158 : * not be set.
159 : *
160 : * INIT_FLAG_SYNC_LOAD: The container is being loaded synchronously, so
161 : * it should avoid relying on async workers to get the container ready.
162 : */
163 : static const uint32_t INIT_FLAG_NONE = 0x0;
164 : static const uint32_t INIT_FLAG_DISCARDABLE = 0x1;
165 : static const uint32_t INIT_FLAG_DECODE_IMMEDIATELY = 0x2;
166 : static const uint32_t INIT_FLAG_TRANSIENT = 0x4;
167 : static const uint32_t INIT_FLAG_SYNC_LOAD = 0x8;
168 :
169 : virtual already_AddRefed<ProgressTracker> GetProgressTracker() = 0;
170 0 : virtual void SetProgressTracker(ProgressTracker* aProgressTracker) {}
171 :
172 : /**
173 : * The size, in bytes, occupied by the compressed source data of the image.
174 : * If MallocSizeOf does not work on this platform, uses a fallback approach to
175 : * ensure that something reasonable is always returned.
176 : */
177 : virtual size_t
178 : SizeOfSourceWithComputedFallback(SizeOfState& aState) const = 0;
179 :
180 : /**
181 : * Collect an accounting of the memory occupied by the image's surfaces (which
182 : * together make up its decoded data). Each surface is recorded as a separate
183 : * SurfaceMemoryCounter, stored in @aCounters.
184 : */
185 : virtual void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters,
186 : MallocSizeOf aMallocSizeOf) const = 0;
187 :
188 : virtual void IncrementAnimationConsumers() = 0;
189 : virtual void DecrementAnimationConsumers() = 0;
190 : #ifdef DEBUG
191 : virtual uint32_t GetAnimationConsumers() = 0;
192 : #endif
193 :
194 : /**
195 : * Called from OnDataAvailable when the stream associated with the image has
196 : * received new image data. The arguments are the same as OnDataAvailable's,
197 : * but by separating this functionality into a different method we don't
198 : * interfere with subclasses which wish to implement nsIStreamListener.
199 : *
200 : * Images should not do anything that could send out notifications until they
201 : * have received their first OnImageDataAvailable notification; in
202 : * particular, this means that instantiating decoders should be deferred
203 : * until OnImageDataAvailable is called.
204 : */
205 : virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
206 : nsISupports* aContext,
207 : nsIInputStream* aInStr,
208 : uint64_t aSourceOffset,
209 : uint32_t aCount) = 0;
210 :
211 : /**
212 : * Called from OnStopRequest when the image's underlying request completes.
213 : *
214 : * @param aRequest The completed request.
215 : * @param aContext Context from Necko's OnStopRequest.
216 : * @param aStatus A success or failure code.
217 : * @param aLastPart Whether this is the final part of the underlying request.
218 : */
219 : virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
220 : nsISupports* aContext,
221 : nsresult aStatus,
222 : bool aLastPart) = 0;
223 :
224 : /**
225 : * Called when the SurfaceCache discards a surface belonging to this image.
226 : */
227 : virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) = 0;
228 :
229 : virtual void SetInnerWindowID(uint64_t aInnerWindowId) = 0;
230 : virtual uint64_t InnerWindowID() const = 0;
231 :
232 : virtual bool HasError() = 0;
233 : virtual void SetHasError() = 0;
234 :
235 : virtual nsIURI* GetURI() const = 0;
236 :
237 0 : virtual void ReportUseCounters() { }
238 : };
239 :
240 : class ImageResource : public Image
241 : {
242 : public:
243 328 : already_AddRefed<ProgressTracker> GetProgressTracker() override
244 : {
245 656 : RefPtr<ProgressTracker> progressTracker = mProgressTracker;
246 0 : MOZ_ASSERT(progressTracker);
247 0 : return progressTracker.forget();
248 : }
249 :
250 20 : void SetProgressTracker(ProgressTracker* aProgressTracker) final
251 : {
252 20 : MOZ_ASSERT(aProgressTracker);
253 0 : MOZ_ASSERT(!mProgressTracker);
254 0 : mProgressTracker = aProgressTracker;
255 0 : }
256 :
257 : virtual void IncrementAnimationConsumers() override;
258 : virtual void DecrementAnimationConsumers() override;
259 : #ifdef DEBUG
260 0 : virtual uint32_t GetAnimationConsumers() override
261 : {
262 0 : return mAnimationConsumers;
263 : }
264 : #endif
265 :
266 0 : virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) override { }
267 :
268 16 : virtual void SetInnerWindowID(uint64_t aInnerWindowId) override
269 : {
270 16 : mInnerWindowId = aInnerWindowId;
271 0 : }
272 0 : virtual uint64_t InnerWindowID() const override { return mInnerWindowId; }
273 :
274 20 : virtual bool HasError() override { return mError; }
275 0 : virtual void SetHasError() override { mError = true; }
276 :
277 : /*
278 : * Returns a non-AddRefed pointer to the URI associated with this image.
279 : * Illegal to use off-main-thread.
280 : */
281 18 : nsIURI* GetURI() const override { return mURI; }
282 :
283 : protected:
284 : explicit ImageResource(nsIURI* aURI);
285 : ~ImageResource();
286 :
287 : bool GetSpecTruncatedTo1k(nsCString& aSpec) const;
288 :
289 : // Shared functionality for implementors of imgIContainer. Every
290 : // implementation of attribute animationMode should forward here.
291 : nsresult GetAnimationModeInternal(uint16_t* aAnimationMode);
292 : nsresult SetAnimationModeInternal(uint16_t aAnimationMode);
293 :
294 : /**
295 : * Helper for RequestRefresh.
296 : *
297 : * If we've had a "recent" refresh (i.e. if this image is being used in
298 : * multiple documents & some other document *just* called RequestRefresh() on
299 : * this image with a timestamp close to aTime), this method returns true.
300 : *
301 : * Otherwise, this method updates mLastRefreshTime to aTime & returns false.
302 : */
303 : bool HadRecentRefresh(const TimeStamp& aTime);
304 :
305 : /**
306 : * Decides whether animation should or should not be happening,
307 : * and makes sure the right thing is being done.
308 : */
309 : virtual void EvaluateAnimation();
310 :
311 : /**
312 : * Extended by child classes, if they have additional
313 : * conditions for being able to animate.
314 : */
315 0 : virtual bool ShouldAnimate() {
316 13 : return mAnimationConsumers > 0 && mAnimationMode != kDontAnimMode;
317 : }
318 :
319 : virtual nsresult StartAnimation() = 0;
320 : virtual nsresult StopAnimation() = 0;
321 :
322 : void SendOnUnlockedDraw(uint32_t aFlags);
323 :
324 : #ifdef DEBUG
325 : // Records the image drawing for startup performance testing.
326 : void NotifyDrawingObservers();
327 : #endif
328 :
329 : // Member data shared by all implementations of this abstract class
330 : RefPtr<ProgressTracker> mProgressTracker;
331 : nsCOMPtr<nsIURI> mURI;
332 : TimeStamp mLastRefreshTime;
333 : uint64_t mInnerWindowId;
334 : uint32_t mAnimationConsumers;
335 : uint16_t mAnimationMode; // Enum values in imgIContainer
336 : bool mInitialized:1; // Have we been initalized?
337 : bool mAnimating:1; // Are we currently animating?
338 : bool mError:1; // Error handling
339 :
340 : virtual Tuple<ImgDrawResult, gfx::IntSize, RefPtr<gfx::SourceSurface>>
341 0 : GetFrameInternal(const gfx::IntSize& aSize,
342 : const Maybe<SVGImageContext>& aSVGContext,
343 : uint32_t aWhichFrame,
344 : uint32_t aFlags)
345 : {
346 : return MakeTuple(ImgDrawResult::BAD_IMAGE, aSize,
347 0 : RefPtr<gfx::SourceSurface>());
348 : }
349 :
350 : /**
351 : * Calculate the estimated size to use for an image container with the given
352 : * parameters. It may not be the same as the given size, and it may not be
353 : * the same as the size of the surface in the image container, but it is the
354 : * best effort estimate.
355 : */
356 0 : virtual gfx::IntSize GetImageContainerSize(layers::LayerManager* aManager,
357 : const gfx::IntSize& aSize,
358 : uint32_t aFlags)
359 : {
360 0 : return gfx::IntSize(0, 0);
361 : }
362 :
363 : already_AddRefed<layers::ImageContainer>
364 : GetImageContainerImpl(layers::LayerManager* aManager,
365 : const gfx::IntSize& aSize,
366 : const Maybe<SVGImageContext>& aSVGContext,
367 : uint32_t aFlags);
368 :
369 : void UpdateImageContainer();
370 :
371 : void ReleaseImageContainer();
372 :
373 : private:
374 : void SetCurrentImage(layers::ImageContainer* aContainer,
375 : gfx::SourceSurface* aSurface,
376 : bool aInTransaction);
377 :
378 0 : struct ImageContainerEntry {
379 0 : ImageContainerEntry(const gfx::IntSize& aSize,
380 : const Maybe<SVGImageContext>& aSVGContext,
381 : layers::ImageContainer* aContainer,
382 : uint32_t aFlags)
383 0 : : mSize(aSize)
384 : , mSVGContext(aSVGContext)
385 : , mContainer(aContainer)
386 : , mLastDrawResult(ImgDrawResult::NOT_READY)
387 0 : , mFlags(aFlags)
388 : { }
389 :
390 : gfx::IntSize mSize;
391 : Maybe<SVGImageContext> mSVGContext;
392 : // A weak pointer to our ImageContainer, which stays alive only as long as
393 : // the layer system needs it.
394 : WeakPtr<layers::ImageContainer> mContainer;
395 : // If mContainer is non-null, this contains the ImgDrawResult we obtained
396 : // the last time we updated it.
397 : ImgDrawResult mLastDrawResult;
398 : // Cached flags to use for decoding. FLAG_ASYNC_NOTIFY should always be set
399 : // but FLAG_HIGH_QUALITY_SCALING may vary.
400 : uint32_t mFlags;
401 : };
402 :
403 : AutoTArray<ImageContainerEntry, 1> mImageContainers;
404 : layers::ImageContainer::ProducerID mImageProducerID;
405 : layers::ImageContainer::FrameID mLastFrameID;
406 : };
407 :
408 : } // namespace image
409 : } // namespace mozilla
410 :
411 : #endif // mozilla_image_Image_h
|