Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : *
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : /** @file
8 : * This file declares the RasterImage class, which
9 : * handles static and animated rasterized images.
10 : *
11 : * @author Stuart Parmenter <pavlov@netscape.com>
12 : * @author Chris Saari <saari@netscape.com>
13 : * @author Arron Mogge <paper@animecity.nu>
14 : * @author Andrew Smith <asmith15@learn.senecac.on.ca>
15 : */
16 :
17 : #ifndef mozilla_image_RasterImage_h
18 : #define mozilla_image_RasterImage_h
19 :
20 : #include "Image.h"
21 : #include "nsCOMPtr.h"
22 : #include "imgIContainer.h"
23 : #include "nsIProperties.h"
24 : #include "nsTArray.h"
25 : #include "LookupResult.h"
26 : #include "nsThreadUtils.h"
27 : #include "DecodePool.h"
28 : #include "DecoderFactory.h"
29 : #include "FrameAnimator.h"
30 : #include "ImageMetadata.h"
31 : #include "ISurfaceProvider.h"
32 : #include "Orientation.h"
33 : #include "nsIObserver.h"
34 : #include "mozilla/Attributes.h"
35 : #include "mozilla/Maybe.h"
36 : #include "mozilla/MemoryReporting.h"
37 : #include "mozilla/NotNull.h"
38 : #include "mozilla/Pair.h"
39 : #include "mozilla/TimeStamp.h"
40 : #include "mozilla/WeakPtr.h"
41 : #include "mozilla/UniquePtr.h"
42 : #include "ImageContainer.h"
43 : #include "PlaybackType.h"
44 : #ifdef DEBUG
45 : #include "imgIContainerDebug.h"
46 : #endif
47 :
48 : class nsIInputStream;
49 : class nsIRequest;
50 :
51 : #define NS_RASTERIMAGE_CID \
52 : { /* 376ff2c1-9bf6-418a-b143-3340c00112f7 */ \
53 : 0x376ff2c1, \
54 : 0x9bf6, \
55 : 0x418a, \
56 : {0xb1, 0x43, 0x33, 0x40, 0xc0, 0x01, 0x12, 0xf7} \
57 : }
58 :
59 : /**
60 : * Handles static and animated image containers.
61 : *
62 : *
63 : * @par A Quick Walk Through
64 : * The decoder initializes this class and calls AppendFrame() to add a frame.
65 : * Once RasterImage detects more than one frame, it starts the animation
66 : * with StartAnimation(). Note that the invalidation events for RasterImage are
67 : * generated automatically using nsRefreshDriver.
68 : *
69 : * @par
70 : * StartAnimation() initializes the animation helper object and sets the time
71 : * the first frame was displayed to the current clock time.
72 : *
73 : * @par
74 : * When the refresh driver corresponding to the imgIContainer that this image is
75 : * a part of notifies the RasterImage that it's time to invalidate,
76 : * RequestRefresh() is called with a given TimeStamp to advance to. As long as
77 : * the timeout of the given frame (the frame's "delay") plus the time that frame
78 : * was first displayed is less than or equal to the TimeStamp given,
79 : * RequestRefresh() calls AdvanceFrame().
80 : *
81 : * @par
82 : * AdvanceFrame() is responsible for advancing a single frame of the animation.
83 : * It can return true, meaning that the frame advanced, or false, meaning that
84 : * the frame failed to advance (usually because the next frame hasn't been
85 : * decoded yet). It is also responsible for performing the final animation stop
86 : * procedure if the final frame of a non-looping animation is reached.
87 : *
88 : * @par
89 : * Each frame can have a different method of removing itself. These are
90 : * listed as imgIContainer::cDispose... constants. Notify() calls
91 : * DoComposite() to handle any special frame destruction.
92 : *
93 : * @par
94 : * The basic path through DoComposite() is:
95 : * 1) Calculate Area that needs updating, which is at least the area of
96 : * aNextFrame.
97 : * 2) Dispose of previous frame.
98 : * 3) Draw new image onto compositingFrame.
99 : * See comments in DoComposite() for more information and optimizations.
100 : *
101 : * @par
102 : * The rest of the RasterImage specific functions are used by DoComposite to
103 : * destroy the old frame and build the new one.
104 : *
105 : * @note
106 : * <li> "Mask", "Alpha", and "Alpha Level" are interchangeable phrases in
107 : * respects to RasterImage.
108 : *
109 : * @par
110 : * <li> GIFs never have more than a 1 bit alpha.
111 : * <li> APNGs may have a full alpha channel.
112 : *
113 : * @par
114 : * <li> Background color specified in GIF is ignored by web browsers.
115 : *
116 : * @par
117 : * <li> If Frame 3 wants to dispose by restoring previous, what it wants is to
118 : * restore the composition up to and including Frame 2, as well as Frame 2s
119 : * disposal. So, in the middle of DoComposite when composing Frame 3, right
120 : * after destroying Frame 2's area, we copy compositingFrame to
121 : * prevCompositingFrame. When DoComposite gets called to do Frame 4, we
122 : * copy prevCompositingFrame back, and then draw Frame 4 on top.
123 : *
124 : * @par
125 : * The mAnim structure has members only needed for animated images, so
126 : * it's not allocated until the second frame is added.
127 : */
128 :
129 : namespace mozilla {
130 :
131 : namespace layers {
132 : class ImageContainer;
133 : class Image;
134 : } // namespace layers
135 :
136 : namespace image {
137 :
138 : class Decoder;
139 : struct DecoderFinalStatus;
140 : struct DecoderTelemetry;
141 : class ImageMetadata;
142 : class SourceBuffer;
143 :
144 : class RasterImage final : public ImageResource
145 : , public nsIProperties
146 : , public SupportsWeakPtr<RasterImage>
147 : #ifdef DEBUG
148 : , public imgIContainerDebug
149 : #endif
150 : {
151 : // (no public constructor - use ImageFactory)
152 : virtual ~RasterImage();
153 :
154 : public:
155 21 : MOZ_DECLARE_WEAKREFERENCE_TYPENAME(RasterImage)
156 : NS_DECL_THREADSAFE_ISUPPORTS
157 : NS_DECL_NSIPROPERTIES
158 : NS_DECL_IMGICONTAINER
159 : #ifdef DEBUG
160 : NS_DECL_IMGICONTAINERDEBUG
161 : #endif
162 :
163 : nsresult GetNativeSizes(nsTArray<gfx::IntSize>& aNativeSizes) const override;
164 : virtual nsresult StartAnimation() override;
165 : virtual nsresult StopAnimation() override;
166 :
167 : // Methods inherited from Image
168 : virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) override;
169 :
170 : virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf)
171 : const override;
172 : virtual void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters,
173 : MallocSizeOf aMallocSizeOf) const override;
174 :
175 : /* Triggers discarding. */
176 : void Discard();
177 :
178 :
179 : //////////////////////////////////////////////////////////////////////////////
180 : // Decoder callbacks.
181 : //////////////////////////////////////////////////////////////////////////////
182 :
183 : /**
184 : * Sends the provided progress notifications to ProgressTracker.
185 : *
186 : * Main-thread only.
187 : *
188 : * @param aProgress The progress notifications to send.
189 : * @param aInvalidRect An invalidation rect to send.
190 : * @param aFrameCount If Some(), an updated count of the number of frames of
191 : * animation the decoder has finished decoding so far. This
192 : * is a lower bound for the total number of animation
193 : * frames this image has.
194 : * @param aDecoderFlags The decoder flags used by the decoder that generated
195 : * these notifications, or DefaultDecoderFlags() if the
196 : * notifications don't come from a decoder.
197 : * @param aSurfaceFlags The surface flags used by the decoder that generated
198 : * these notifications, or DefaultSurfaceFlags() if the
199 : * notifications don't come from a decoder.
200 : */
201 : void NotifyProgress(Progress aProgress,
202 : const gfx::IntRect& aInvalidRect = nsIntRect(),
203 : const Maybe<uint32_t>& aFrameCount = Nothing(),
204 : DecoderFlags aDecoderFlags = DefaultDecoderFlags(),
205 : SurfaceFlags aSurfaceFlags = DefaultSurfaceFlags());
206 :
207 : /**
208 : * Records decoding results, sends out any final notifications, updates the
209 : * state of this image, and records telemetry.
210 : *
211 : * Main-thread only.
212 : *
213 : * @param aStatus Final status information about the decoder. (Whether it
214 : * encountered an error, etc.)
215 : * @param aMetadata Metadata about this image that the decoder gathered.
216 : * @param aTelemetry Telemetry data about the decoder.
217 : * @param aProgress Any final progress notifications to send.
218 : * @param aInvalidRect Any final invalidation rect to send.
219 : * @param aFrameCount If Some(), a final updated count of the number of frames
220 : * of animation the decoder has finished decoding so far.
221 : * This is a lower bound for the total number of animation
222 : * frames this image has.
223 : * @param aDecoderFlags The decoder flags used by the decoder.
224 : * @param aSurfaceFlags The surface flags used by the decoder.
225 : */
226 : void NotifyDecodeComplete(const DecoderFinalStatus& aStatus,
227 : const ImageMetadata& aMetadata,
228 : const DecoderTelemetry& aTelemetry,
229 : Progress aProgress,
230 : const gfx::IntRect& aInvalidRect,
231 : const Maybe<uint32_t>& aFrameCount,
232 : DecoderFlags aDecoderFlags,
233 : SurfaceFlags aSurfaceFlags);
234 :
235 : // Helper method for NotifyDecodeComplete.
236 : void ReportDecoderError();
237 :
238 :
239 : //////////////////////////////////////////////////////////////////////////////
240 : // Network callbacks.
241 : //////////////////////////////////////////////////////////////////////////////
242 :
243 : virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
244 : nsISupports* aContext,
245 : nsIInputStream* aInStr,
246 : uint64_t aSourceOffset,
247 : uint32_t aCount) override;
248 : virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
249 : nsISupports* aContext,
250 : nsresult aStatus,
251 : bool aLastPart) override;
252 :
253 : void NotifyForLoadEvent(Progress aProgress);
254 :
255 : /**
256 : * A hint of the number of bytes of source data that the image contains. If
257 : * called early on, this can help reduce copying and reallocations by
258 : * appropriately preallocating the source data buffer.
259 : *
260 : * We take this approach rather than having the source data management code do
261 : * something more complicated (like chunklisting) because HTTP is by far the
262 : * dominant source of images, and the Content-Length header is quite reliable.
263 : * Thus, pre-allocation simplifies code and reduces the total number of
264 : * allocations.
265 : */
266 : nsresult SetSourceSizeHint(uint32_t aSizeHint);
267 :
268 14 : nsCString GetURIString() {
269 14 : nsCString spec;
270 14 : if (GetURI()) {
271 14 : GetURI()->GetSpec(spec);
272 : }
273 14 : return spec;
274 : }
275 :
276 : private:
277 : nsresult Init(const char* aMimeType, uint32_t aFlags);
278 :
279 : /**
280 : * Tries to retrieve a surface for this image with size @aSize, surface flags
281 : * matching @aFlags, and a playback type of @aPlaybackType.
282 : *
283 : * If @aFlags specifies FLAG_SYNC_DECODE and we already have all the image
284 : * data, we'll attempt a sync decode if no matching surface is found. If
285 : * FLAG_SYNC_DECODE was not specified and no matching surface was found, we'll
286 : * kick off an async decode so that the surface is (hopefully) available next
287 : * time it's requested.
288 : *
289 : * @return a drawable surface, which may be empty if the requested surface
290 : * could not be found.
291 : */
292 : DrawableSurface LookupFrame(const gfx::IntSize& aSize,
293 : uint32_t aFlags,
294 : PlaybackType aPlaybackType);
295 :
296 : /// Helper method for LookupFrame().
297 : LookupResult LookupFrameInternal(const gfx::IntSize& aSize,
298 : uint32_t aFlags,
299 : PlaybackType aPlaybackType);
300 :
301 : DrawResult DrawInternal(DrawableSurface&& aFrameRef,
302 : gfxContext* aContext,
303 : const nsIntSize& aSize,
304 : const ImageRegion& aRegion,
305 : gfx::SamplingFilter aSamplingFilter,
306 : uint32_t aFlags,
307 : float aOpacity);
308 :
309 : Pair<DrawResult, RefPtr<gfx::SourceSurface>>
310 : GetFrameInternal(const gfx::IntSize& aSize,
311 : uint32_t aWhichFrame,
312 : uint32_t aFlags);
313 :
314 : Pair<DrawResult, RefPtr<layers::Image>>
315 : GetCurrentImage(layers::ImageContainer* aContainer, uint32_t aFlags);
316 :
317 : void UpdateImageContainer();
318 :
319 : //////////////////////////////////////////////////////////////////////////////
320 : // Decoding.
321 : //////////////////////////////////////////////////////////////////////////////
322 :
323 : /**
324 : * Creates and runs a decoder, either synchronously or asynchronously
325 : * according to @aFlags. Decodes at the provided target size @aSize, using
326 : * decode flags @aFlags. Performs a single-frame decode of this image unless
327 : * we know the image is animated *and* @aPlaybackType is
328 : * PlaybackType::eAnimated.
329 : *
330 : * It's an error to call Decode() before this image's intrinsic size is
331 : * available. A metadata decode must successfully complete first.
332 : *
333 : * Returns true of the decode was run synchronously.
334 : */
335 : bool Decode(const gfx::IntSize& aSize,
336 : uint32_t aFlags,
337 : PlaybackType aPlaybackType);
338 :
339 : /**
340 : * Creates and runs a metadata decoder, either synchronously or
341 : * asynchronously according to @aFlags.
342 : */
343 : NS_IMETHOD DecodeMetadata(uint32_t aFlags);
344 :
345 : /**
346 : * Sets the size, inherent orientation, animation metadata, and other
347 : * information about the image gathered during decoding.
348 : *
349 : * This function may be called multiple times, but will throw an error if
350 : * subsequent calls do not match the first.
351 : *
352 : * @param aMetadata The metadata to set on this image.
353 : * @param aFromMetadataDecode True if this metadata came from a metadata
354 : * decode; false if it came from a full decode.
355 : * @return |true| unless a catastrophic failure was discovered. If |false| is
356 : * returned, it indicates that the image is corrupt in a way that requires all
357 : * surfaces to be discarded to recover.
358 : */
359 : bool SetMetadata(const ImageMetadata& aMetadata, bool aFromMetadataDecode);
360 :
361 : /**
362 : * In catastrophic circumstances like a GPU driver crash, the contents of our
363 : * frames may become invalid. If the information we gathered during the
364 : * metadata decode proves to be wrong due to image corruption, the frames we
365 : * have may violate this class's invariants. Either way, we need to
366 : * immediately discard the invalid frames and redecode so that callers don't
367 : * perceive that we've entered an invalid state.
368 : *
369 : * RecoverFromInvalidFrames discards all existing frames and redecodes using
370 : * the provided @aSize and @aFlags.
371 : */
372 : void RecoverFromInvalidFrames(const nsIntSize& aSize, uint32_t aFlags);
373 :
374 : void OnSurfaceDiscardedInternal(bool aAnimatedFramesDiscarded);
375 :
376 : private: // data
377 : nsIntSize mSize;
378 : nsTArray<nsIntSize> mNativeSizes;
379 : Orientation mOrientation;
380 :
381 : /// If this has a value, we're waiting for SetSize() to send the load event.
382 : Maybe<Progress> mLoadProgress;
383 :
384 : nsCOMPtr<nsIProperties> mProperties;
385 :
386 : /// If this image is animated, a FrameAnimator which manages its animation.
387 : UniquePtr<FrameAnimator> mFrameAnimator;
388 :
389 : /// Animation timeline and other state for animation images.
390 : Maybe<AnimationState> mAnimationState;
391 :
392 : // Image locking.
393 : uint32_t mLockCount;
394 :
395 : // The type of decoder this image needs. Computed from the MIME type in Init().
396 : DecoderType mDecoderType;
397 :
398 : // How many times we've decoded this image.
399 : // This is currently only used for statistics
400 : int32_t mDecodeCount;
401 :
402 : // A weak pointer to our ImageContainer, which stays alive only as long as
403 : // the layer system needs it.
404 : WeakPtr<layers::ImageContainer> mImageContainer;
405 :
406 : layers::ImageContainer::ProducerID mImageProducerID;
407 : layers::ImageContainer::FrameID mLastFrameID;
408 :
409 : // If mImageContainer is non-null, this contains the DrawResult we obtained
410 : // the last time we updated it.
411 : DrawResult mLastImageContainerDrawResult;
412 :
413 : #ifdef DEBUG
414 : uint32_t mFramesNotified;
415 : #endif
416 :
417 : // The source data for this image.
418 : NotNull<RefPtr<SourceBuffer>> mSourceBuffer;
419 :
420 : // Boolean flags (clustered together to conserve space):
421 : bool mHasSize:1; // Has SetSize() been called?
422 : bool mTransient:1; // Is the image short-lived?
423 : bool mSyncLoad:1; // Are we loading synchronously?
424 : bool mDiscardable:1; // Is container discardable?
425 : bool mSomeSourceData:1; // Do we have some source data?
426 : bool mAllSourceData:1; // Do we have all the source data?
427 : bool mHasBeenDecoded:1; // Decoded at least once?
428 :
429 : // Whether we're waiting to start animation. If we get a StartAnimation() call
430 : // but we don't yet have more than one frame, mPendingAnimation is set so that
431 : // we know to start animation later if/when we have more frames.
432 : bool mPendingAnimation:1;
433 :
434 : // Whether the animation can stop, due to running out
435 : // of frames, or no more owning request
436 : bool mAnimationFinished:1;
437 :
438 : // Whether, once we are done doing a metadata decode, we should immediately
439 : // kick off a full decode.
440 : bool mWantFullDecode:1;
441 :
442 : TimeStamp mDrawStartTime;
443 :
444 :
445 : //////////////////////////////////////////////////////////////////////////////
446 : // Scaling.
447 : //////////////////////////////////////////////////////////////////////////////
448 :
449 : // Determines whether we can downscale during decode with the given
450 : // parameters.
451 : bool CanDownscaleDuringDecode(const nsIntSize& aSize, uint32_t aFlags);
452 :
453 :
454 : // Error handling.
455 : void DoError();
456 :
457 0 : class HandleErrorWorker : public Runnable
458 : {
459 : public:
460 : /**
461 : * Called from decoder threads when DoError() is called, since errors can't
462 : * be handled safely off-main-thread. Dispatches an event which reinvokes
463 : * DoError on the main thread if there isn't one already pending.
464 : */
465 : static void DispatchIfNeeded(RasterImage* aImage);
466 :
467 : NS_IMETHOD Run();
468 :
469 : private:
470 : explicit HandleErrorWorker(RasterImage* aImage);
471 :
472 : RefPtr<RasterImage> mImage;
473 : };
474 :
475 : // Helpers
476 : bool CanDiscard();
477 :
478 : bool IsOpaque();
479 :
480 : DrawableSurface RequestDecodeForSizeInternal(const gfx::IntSize& aSize, uint32_t aFlags);
481 :
482 : protected:
483 : explicit RasterImage(ImageURL* aURI = nullptr);
484 :
485 : bool ShouldAnimate() override;
486 :
487 : friend class ImageFactory;
488 : };
489 :
490 : inline NS_IMETHODIMP
491 0 : RasterImage::GetAnimationMode(uint16_t* aAnimationMode) {
492 0 : return GetAnimationModeInternal(aAnimationMode);
493 : }
494 :
495 : } // namespace image
496 : } // namespace mozilla
497 :
498 : /**
499 : * Casting RasterImage to nsISupports is ambiguous. This method handles that.
500 : */
501 : inline nsISupports*
502 33 : ToSupports(mozilla::image::RasterImage* p)
503 : {
504 33 : return NS_ISUPPORTS_CAST(mozilla::image::ImageResource*, p);
505 : }
506 :
507 : #endif /* mozilla_image_RasterImage_h */
|