RasterImage.h 19 KB

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