/src/mozilla-central/image/Image.h
Line | Count | Source (jump to first uncovered line) |
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 | | : mSource(0) |
36 | | , mDecodedHeap(0) |
37 | | , mDecodedNonHeap(0) |
38 | | , mExternalHandles(0) |
39 | 0 | { } |
40 | | |
41 | 0 | void SetSource(size_t aCount) { mSource = aCount; } |
42 | 0 | size_t Source() const { return mSource; } |
43 | 0 | void SetDecodedHeap(size_t aCount) { mDecodedHeap = aCount; } |
44 | 0 | size_t DecodedHeap() const { return mDecodedHeap; } |
45 | 0 | void SetDecodedNonHeap(size_t aCount) { mDecodedNonHeap = aCount; } |
46 | 0 | size_t DecodedNonHeap() const { return mDecodedNonHeap; } |
47 | 0 | void SetExternalHandles(size_t aCount) { mExternalHandles = aCount; } |
48 | 0 | size_t ExternalHandles() const { return mExternalHandles; } |
49 | | |
50 | | MemoryCounter& operator+=(const MemoryCounter& aOther) |
51 | 0 | { |
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 | 0 | } |
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 | | struct SurfaceMemoryCounter |
74 | | { |
75 | | SurfaceMemoryCounter(const SurfaceKey& aKey, |
76 | | bool aIsLocked, |
77 | | bool aCannotSubstitute, |
78 | | bool aIsFactor2, |
79 | | SurfaceMemoryCounterType aType = |
80 | | SurfaceMemoryCounterType::NORMAL) |
81 | | : mKey(aKey) |
82 | | , mType(aType) |
83 | | , mIsLocked(aIsLocked) |
84 | | , mCannotSubstitute(aCannotSubstitute) |
85 | | , mIsFactor2(aIsFactor2) |
86 | 0 | { } |
87 | | |
88 | 0 | const SurfaceKey& Key() const { return mKey; } |
89 | 0 | MemoryCounter& Values() { return mValues; } |
90 | 0 | const MemoryCounter& Values() const { return mValues; } |
91 | 0 | SurfaceMemoryCounterType Type() const { return mType; } |
92 | 0 | bool IsLocked() const { return mIsLocked; } |
93 | 0 | bool CannotSubstitute() const { return mCannotSubstitute; } |
94 | 0 | 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 | | struct ImageMemoryCounter |
106 | | { |
107 | | ImageMemoryCounter(Image* aImage, SizeOfState& aState, bool aIsUsed); |
108 | | |
109 | 0 | nsCString& URI() { return mURI; } |
110 | 0 | const nsCString& URI() const { return mURI; } |
111 | 0 | 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 | 0 | uint16_t Type() const { return mType; } |
115 | 0 | bool IsUsed() const { return mIsUsed; } |
116 | | |
117 | | bool IsNotable() const |
118 | 0 | { |
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 | 0 | } |
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 | | 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 | | already_AddRefed<ProgressTracker> GetProgressTracker() override |
244 | 0 | { |
245 | 0 | RefPtr<ProgressTracker> progressTracker = mProgressTracker; |
246 | 0 | MOZ_ASSERT(progressTracker); |
247 | 0 | return progressTracker.forget(); |
248 | 0 | } |
249 | | |
250 | | void SetProgressTracker(ProgressTracker* aProgressTracker) final |
251 | 0 | { |
252 | 0 | 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 | | virtual uint32_t GetAnimationConsumers() override |
261 | | { |
262 | | return mAnimationConsumers; |
263 | | } |
264 | | #endif |
265 | | |
266 | 0 | virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) override { } |
267 | | |
268 | | virtual void SetInnerWindowID(uint64_t aInnerWindowId) override |
269 | 0 | { |
270 | 0 | mInnerWindowId = aInnerWindowId; |
271 | 0 | } |
272 | 0 | virtual uint64_t InnerWindowID() const override { return mInnerWindowId; } |
273 | | |
274 | 0 | 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 | 0 | 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 | 0 | return mAnimationConsumers > 0 && mAnimationMode != kDontAnimMode; |
317 | 0 | } |
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 | | /** |
341 | | * Attempt to find a matching cached surface in the SurfaceCache, and if not |
342 | | * available, request the production of such a surface (either synchronously |
343 | | * or asynchronously). |
344 | | * |
345 | | * If the draw result is BAD_IMAGE, BAD_ARGS or NOT_READY, the size will be |
346 | | * the same as aSize. If it is TEMPORARY_ERROR, INCOMPLETE, or SUCCESS, the |
347 | | * size is a hint as to what we expect the surface size to be, once the best |
348 | | * fitting size is available. It may or may not match the size of the surface |
349 | | * returned at this moment. This is useful for choosing how to store the final |
350 | | * result (e.g. if going into an ImageContainer, ideally we would share the |
351 | | * same container for many requested sizes, if they all end up with the same |
352 | | * best fit size in the end). |
353 | | * |
354 | | * A valid surface should only be returned for SUCCESS and INCOMPLETE. |
355 | | * |
356 | | * Any other draw result is invalid. |
357 | | */ |
358 | | virtual Tuple<ImgDrawResult, gfx::IntSize, RefPtr<gfx::SourceSurface>> |
359 | | GetFrameInternal(const gfx::IntSize& aSize, |
360 | | const Maybe<SVGImageContext>& aSVGContext, |
361 | | uint32_t aWhichFrame, |
362 | | uint32_t aFlags) |
363 | 0 | { |
364 | 0 | return MakeTuple(ImgDrawResult::BAD_IMAGE, aSize, |
365 | 0 | RefPtr<gfx::SourceSurface>()); |
366 | 0 | } |
367 | | |
368 | | /** |
369 | | * Calculate the estimated size to use for an image container with the given |
370 | | * parameters. It may not be the same as the given size, and it may not be |
371 | | * the same as the size of the surface in the image container, but it is the |
372 | | * best effort estimate. |
373 | | */ |
374 | | virtual Tuple<ImgDrawResult, gfx::IntSize> |
375 | | GetImageContainerSize(layers::LayerManager* aManager, |
376 | | const gfx::IntSize& aSize, |
377 | | uint32_t aFlags) |
378 | 0 | { |
379 | 0 | return MakeTuple(ImgDrawResult::NOT_SUPPORTED, gfx::IntSize(0, 0)); |
380 | 0 | } |
381 | | |
382 | | ImgDrawResult GetImageContainerImpl(layers::LayerManager* aManager, |
383 | | const gfx::IntSize& aSize, |
384 | | const Maybe<SVGImageContext>& aSVGContext, |
385 | | uint32_t aFlags, |
386 | | layers::ImageContainer** aContainer); |
387 | | |
388 | | void UpdateImageContainer(); |
389 | | |
390 | | void ReleaseImageContainer(); |
391 | | |
392 | | private: |
393 | | void SetCurrentImage(layers::ImageContainer* aContainer, |
394 | | gfx::SourceSurface* aSurface, |
395 | | bool aInTransaction); |
396 | | |
397 | | struct ImageContainerEntry { |
398 | | ImageContainerEntry(const gfx::IntSize& aSize, |
399 | | const Maybe<SVGImageContext>& aSVGContext, |
400 | | layers::ImageContainer* aContainer, |
401 | | uint32_t aFlags) |
402 | | : mSize(aSize) |
403 | | , mSVGContext(aSVGContext) |
404 | | , mContainer(aContainer) |
405 | | , mLastDrawResult(ImgDrawResult::NOT_READY) |
406 | | , mFlags(aFlags) |
407 | 0 | { } |
408 | | |
409 | | gfx::IntSize mSize; |
410 | | Maybe<SVGImageContext> mSVGContext; |
411 | | // A weak pointer to our ImageContainer, which stays alive only as long as |
412 | | // the layer system needs it. |
413 | | WeakPtr<layers::ImageContainer> mContainer; |
414 | | // If mContainer is non-null, this contains the ImgDrawResult we obtained |
415 | | // the last time we updated it. |
416 | | ImgDrawResult mLastDrawResult; |
417 | | // Cached flags to use for decoding. FLAG_ASYNC_NOTIFY should always be set |
418 | | // but FLAG_HIGH_QUALITY_SCALING may vary. |
419 | | uint32_t mFlags; |
420 | | }; |
421 | | |
422 | | AutoTArray<ImageContainerEntry, 1> mImageContainers; |
423 | | layers::ImageContainer::ProducerID mImageProducerID; |
424 | | layers::ImageContainer::FrameID mLastFrameID; |
425 | | }; |
426 | | |
427 | | } // namespace image |
428 | | } // namespace mozilla |
429 | | |
430 | | #endif // mozilla_image_Image_h |