Fix typo in 9b54bd30006c008b4a951331b273613d5bac3abf
[pm.git] / image / src / Decoder.h
blob42c56f201ff9eea8026a814c02ec16a9ee6e346a
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_IMAGELIB_DECODER_H_
7 #define MOZILLA_IMAGELIB_DECODER_H_
9 #include "FrameAnimator.h"
10 #include "RasterImage.h"
11 #include "mozilla/RefPtr.h"
12 #include "DecodePool.h"
13 #include "ImageMetadata.h"
14 #include "Orientation.h"
15 #include "SourceBuffer.h"
17 namespace mozilla {
19 namespace Telemetry {
20 enum ID : uint32_t;
23 namespace image {
25 class Decoder : public IResumable
27 public:
29 explicit Decoder(RasterImage* aImage);
31 /**
32 * Initialize an image decoder. Decoders may not be re-initialized.
34 void Init();
36 /**
37 * Initializes a decoder whose image and observer is already being used by a
38 * parent decoder. Decoders may not be re-initialized.
40 * Notifications Sent: TODO
42 void InitSharedDecoder(uint8_t* aImageData, uint32_t aImageDataLength,
43 uint32_t* aColormap, uint32_t aColormapSize,
44 RawAccessFrameRef&& aFrameRef);
46 /**
47 * Decodes, reading all data currently available in the SourceBuffer. If more
48 * If aBuffer is null and aCount is 0, Write() flushes any buffered data to
49 * the decoder. Data is buffered if the decoder wasn't able to completely
50 * decode it because it needed a new frame. If it's necessary to flush data,
51 * NeedsToFlushData() will return true.
53 * data is needed, Decode() automatically ensures that it will be called again
54 * on a DecodePool thread when the data becomes available.
56 * Any errors are reported by setting the appropriate state on the decoder.
58 nsresult Decode();
60 /**
61 * Cleans up the decoder's state and notifies our image about success or
62 * failure. May only be called on the main thread.
64 void Finish();
66 /**
67 * Given a maximum number of bytes we're willing to decode, @aByteLimit,
68 * returns true if we should attempt to run this decoder synchronously.
70 bool ShouldSyncDecode(size_t aByteLimit);
72 /**
73 * Informs the shared decoder that all the data has been written.
74 * Should only be used if InitSharedDecoder was useed
76 * Notifications Sent: TODO
78 void FinishSharedDecoder();
80 /**
81 * Gets the invalidation region accumulated by the decoder so far, and clears
82 * the decoder's invalidation region. This means that each call to
83 * TakeInvalidRect() returns only the invalidation region accumulated since
84 * the last call to TakeInvalidRect().
86 nsIntRect TakeInvalidRect()
88 nsIntRect invalidRect = mInvalidRect;
89 mInvalidRect.SetEmpty();
90 return invalidRect;
93 /**
94 * Gets the progress changes accumulated by the decoder so far, and clears
95 * them. This means that each call to TakeProgress() returns only the changes
96 * accumulated since the last call to TakeProgress().
98 Progress TakeProgress()
100 Progress progress = mProgress;
101 mProgress = NoProgress;
102 return progress;
106 * Returns true if there's any progress to report.
108 bool HasProgress() const
110 return mProgress != NoProgress || !mInvalidRect.IsEmpty();
113 // We're not COM-y, so we don't get refcounts by default
114 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Decoder, override)
116 // Implement IResumable.
117 virtual void Resume() override;
120 * State.
123 // If we're doing a "size decode", we more or less pass through the image
124 // data, stopping only to scoop out the image dimensions. A size decode
125 // must be enabled by SetSizeDecode() _before_calling Init().
126 bool IsSizeDecode() { return mSizeDecode; }
127 void SetSizeDecode(bool aSizeDecode)
129 MOZ_ASSERT(!mInitialized, "Shouldn't be initialized yet");
130 mSizeDecode = aSizeDecode;
134 * If this decoder supports downscale-during-decode, sets the target size that
135 * this image should be decoded to.
137 * If this decoder *doesn't* support downscale-during-decode, returns
138 * NS_ERROR_NOT_AVAILABLE. If the provided size is unacceptable, returns
139 * another error.
141 * Returning NS_OK from this method is a promise that the decoder will decode
142 * the image to the requested target size unless it encounters an error.
144 * This must be called before Init() is called.
146 virtual nsresult SetTargetSize(const nsIntSize& aSize)
148 return NS_ERROR_NOT_AVAILABLE;
152 * Set whether should send partial invalidations.
154 * If @aSend is true, we'll send partial invalidations when decoding the first
155 * frame of the image, so image notifications observers will be able to
156 * gradually draw in the image as it downloads.
158 * If @aSend is false (the default), we'll only send an invalidation when we
159 * complete the first frame.
161 * This must be called before Init() is called.
163 void SetSendPartialInvalidations(bool aSend)
165 MOZ_ASSERT(!mInitialized, "Shouldn't be initialized yet");
166 mSendPartialInvalidations = aSend;
170 * Set an iterator to the SourceBuffer which will feed data to this decoder.
172 * This should be called for almost all decoders; the exceptions are the
173 * contained decoders of an nsICODecoder, which will be fed manually via Write
174 * instead.
176 * This must be called before Init() is called.
178 void SetIterator(SourceBufferIterator&& aIterator)
180 MOZ_ASSERT(!mInitialized, "Shouldn't be initialized yet");
181 mIterator.emplace(Move(aIterator));
185 * Set whether this decoder is associated with a transient image. The decoder
186 * may choose to avoid certain optimizations that don't pay off for
187 * short-lived images in this case.
189 void SetImageIsTransient(bool aIsTransient)
191 MOZ_ASSERT(!mInitialized, "Shouldn't be initialized yet");
192 mImageIsTransient = aIsTransient;
196 * Set whether the image is locked for the lifetime of this decoder. We lock
197 * the image during our initial decode to ensure that we don't evict any
198 * surfaces before we realize that the image is animated.
200 void SetImageIsLocked()
202 MOZ_ASSERT(!mInitialized, "Shouldn't be initialized yet");
203 mImageIsLocked = true;
206 bool ImageIsLocked() const { return mImageIsLocked; }
208 size_t BytesDecoded() const { return mBytesDecoded; }
210 // The amount of time we've spent inside Write() so far for this decoder.
211 TimeDuration DecodeTime() const { return mDecodeTime; }
213 // The number of times Write() has been called so far for this decoder.
214 uint32_t ChunkCount() const { return mChunkCount; }
216 // The number of frames we have, including anything in-progress. Thus, this
217 // is only 0 if we haven't begun any frames.
218 uint32_t GetFrameCount() { return mFrameCount; }
220 // The number of complete frames we have (ie, not including anything in-progress).
221 uint32_t GetCompleteFrameCount() { return mInFrame ? mFrameCount - 1 : mFrameCount; }
223 // Error tracking
224 bool HasError() const { return HasDataError() || HasDecoderError(); }
225 bool HasDataError() const { return mDataError; }
226 bool HasDecoderError() const { return NS_FAILED(mFailCode); }
227 nsresult GetDecoderError() const { return mFailCode; }
228 void PostResizeError() { PostDataError(); }
230 bool GetDecodeDone() const
232 return mDecodeDone || (mSizeDecode && HasSize()) || HasError() || mDataDone;
236 * Returns true if this decoder was aborted.
238 * This may happen due to a low-memory condition, or because another decoder
239 * was racing with this one to decode the same frames with the same flags and
240 * this decoder lost the race. Either way, this is not a permanent situation
241 * and does not constitute an error, so we don't report any errors when this
242 * happens.
244 bool WasAborted() const { return mDecodeAborted; }
246 enum DecodeStyle {
247 PROGRESSIVE, // produce intermediate frames representing the partial state of the image
248 SEQUENTIAL // decode to final image immediately
251 void SetFlags(uint32_t aFlags) { mFlags = aFlags; }
252 uint32_t GetFlags() const { return mFlags; }
253 uint32_t GetDecodeFlags() const { return DecodeFlags(mFlags); }
255 bool HasSize() const { return mImageMetadata.HasSize(); }
256 void SetSizeOnImage();
258 void SetSize(const nsIntSize& aSize, const Orientation& aOrientation)
260 PostSize(aSize.width, aSize.height, aOrientation);
263 nsIntSize GetSize() const
265 MOZ_ASSERT(HasSize());
266 return mImageMetadata.GetSize();
269 virtual Telemetry::ID SpeedHistogram();
271 ImageMetadata& GetImageMetadata() { return mImageMetadata; }
274 * Returns a weak pointer to the image associated with this decoder.
276 RasterImage* GetImage() const { MOZ_ASSERT(mImage); return mImage.get(); }
278 // Tell the decoder infrastructure to allocate a frame. By default, frame 0
279 // is created as an ARGB frame with no offset and with size width * height.
280 // If decoders need something different, they must ask for it.
281 // This is called by decoders when they need a new frame. These decoders
282 // must then save the data they have been sent but not yet processed and
283 // return from WriteInternal. When the new frame is created, WriteInternal
284 // will be called again with nullptr and 0 as arguments.
285 void NeedNewFrame(uint32_t frameNum, uint32_t x_offset, uint32_t y_offset,
286 uint32_t width, uint32_t height,
287 gfx::SurfaceFormat format,
288 uint8_t palette_depth = 0);
289 virtual bool NeedsNewFrame() const { return mNeedsNewFrame; }
292 // Try to allocate a frame as described in mNewFrameData and return the
293 // status code from that attempt. Clears mNewFrameData.
294 virtual nsresult AllocateFrame(const nsIntSize& aTargetSize = nsIntSize());
296 already_AddRefed<imgFrame> GetCurrentFrame()
298 nsRefPtr<imgFrame> frame = mCurrentFrame.get();
299 return frame.forget();
302 RawAccessFrameRef GetCurrentFrameRef()
304 return mCurrentFrame ? mCurrentFrame->RawAccessRef()
305 : RawAccessFrameRef();
309 * Writes data to the decoder. Only public for the benefit of nsICODecoder;
310 * other callers should use Decode().
312 * @param aBuffer buffer containing the data to be written
313 * @param aCount the number of bytes to write
315 * Any errors are reported by setting the appropriate state on the decoder.
317 void Write(const char* aBuffer, uint32_t aCount);
320 protected:
321 virtual ~Decoder();
324 * Internal hooks. Decoder implementations may override these and
325 * only these methods.
327 virtual void InitInternal();
328 virtual void WriteInternal(const char* aBuffer, uint32_t aCount);
329 virtual void FinishInternal();
332 * Progress notifications.
335 // Called by decoders when they determine the size of the image. Informs
336 // the image of its size and sends notifications.
337 void PostSize(int32_t aWidth,
338 int32_t aHeight,
339 Orientation aOrientation = Orientation());
341 // Called by decoders if they determine that the image has transparency.
343 // This should be fired as early as possible to allow observers to do things
344 // that affect content, so it's necessarily pessimistic - if there's a
345 // possibility that the image has transparency, for example because its header
346 // specifies that it has an alpha channel, we fire PostHasTransparency
347 // immediately. PostFrameStop's aFrameOpacity argument, on the other hand, is
348 // only used internally to ImageLib. Because PostFrameStop isn't delivered
349 // until the entire frame has been decoded, decoders may take into account the
350 // actual contents of the frame and give a more accurate result.
351 void PostHasTransparency();
353 // Called by decoders when they begin a frame. Informs the image, sends
354 // notifications, and does internal book-keeping.
355 void PostFrameStart();
357 // Called by decoders when they end a frame. Informs the image, sends
358 // notifications, and does internal book-keeping.
359 // Specify whether this frame is opaque as an optimization.
360 // For animated images, specify the disposal, blend method and timeout for
361 // this frame.
362 void PostFrameStop(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
363 DisposalMethod aDisposalMethod = DisposalMethod::KEEP,
364 int32_t aTimeout = 0,
365 BlendMethod aBlendMethod = BlendMethod::OVER);
368 * Called by the decoders when they have a region to invalidate. We may not
369 * actually pass these invalidations on right away.
371 * @param aRect The invalidation rect in the coordinate system of the unscaled
372 * image (that is, the image at its intrinsic size).
373 * @param aRectAtTargetSize If not Nothing(), the invalidation rect in the
374 * coordinate system of the scaled image (that is,
375 * the image at our target decoding size). This must
376 * be supplied if we're downscaling during decode.
378 void PostInvalidation(const nsIntRect& aRect,
379 const Maybe<nsIntRect>& aRectAtTargetSize = Nothing());
381 // Called by the decoders when they have successfully decoded the image. This
382 // may occur as the result of the decoder getting to the appropriate point in
383 // the stream, or by us calling FinishInternal().
385 // May not be called mid-frame.
387 // For animated images, specify the loop count. -1 means loop forever, 0
388 // means a single iteration, stopping on the last frame.
389 void PostDecodeDone(int32_t aLoopCount = 0);
391 // Data errors are the fault of the source data, decoder errors are our fault
392 void PostDataError();
393 void PostDecoderError(nsresult aFailCode);
395 // Returns true if we may have stored data that we need to flush now that we
396 // have a new frame to decode into. Callers can use Write() to actually
397 // flush the data; see the documentation for that method.
398 bool NeedsToFlushData() const { return mNeedsToFlushData; }
401 * CompleteDecode() finishes up the decoding process after Decode() determines
402 * that we're finished. It records final progress and does all the cleanup
403 * that's possible off-main-thread.
405 void CompleteDecode();
408 * Ensures that a given frame number exists with the given parameters, and
409 * returns a RawAccessFrameRef for that frame.
410 * It is not possible to create sparse frame arrays; you can only append
411 * frames to the current frame array, or if there is only one frame in the
412 * array, replace that frame.
413 * @aTargetSize specifies the target size we're decoding to. If we're not
414 * downscaling during decode, this will always be the same as the image's
415 * intrinsic size.
417 * If a non-paletted frame is desired, pass 0 for aPaletteDepth.
419 RawAccessFrameRef EnsureFrame(uint32_t aFrameNum,
420 const nsIntSize& aTargetSize,
421 const nsIntRect& aFrameRect,
422 uint32_t aDecodeFlags,
423 gfx::SurfaceFormat aFormat,
424 uint8_t aPaletteDepth,
425 imgFrame* aPreviousFrame);
427 RawAccessFrameRef InternalAddFrame(uint32_t aFrameNum,
428 const nsIntSize& aTargetSize,
429 const nsIntRect& aFrameRect,
430 uint32_t aDecodeFlags,
431 gfx::SurfaceFormat aFormat,
432 uint8_t aPaletteDepth,
433 imgFrame* aPreviousFrame);
436 * Member variables.
439 nsRefPtr<RasterImage> mImage;
440 Maybe<SourceBufferIterator> mIterator;
441 RawAccessFrameRef mCurrentFrame;
442 ImageMetadata mImageMetadata;
443 nsIntRect mInvalidRect; // Tracks an invalidation region in the current frame.
444 Progress mProgress;
446 uint8_t* mImageData; // Pointer to image data in either Cairo or 8bit format
447 uint32_t mImageDataLength;
448 uint32_t* mColormap; // Current colormap to be used in Cairo format
449 uint32_t mColormapSize;
451 // Telemetry data for this decoder.
452 TimeDuration mDecodeTime;
453 uint32_t mChunkCount;
455 uint32_t mFlags;
456 size_t mBytesDecoded;
457 bool mSendPartialInvalidations;
458 bool mDataDone;
459 bool mDecodeDone;
460 bool mDataError;
461 bool mDecodeAborted;
462 bool mShouldReportError;
463 bool mImageIsTransient;
464 bool mImageIsLocked;
466 private:
467 uint32_t mFrameCount; // Number of frames, including anything in-progress
469 nsresult mFailCode;
471 struct NewFrameData
473 NewFrameData() { }
475 NewFrameData(uint32_t aFrameNum, const nsIntRect& aFrameRect,
476 gfx::SurfaceFormat aFormat, uint8_t aPaletteDepth)
477 : mFrameNum(aFrameNum)
478 , mFrameRect(aFrameRect)
479 , mFormat(aFormat)
480 , mPaletteDepth(aPaletteDepth)
483 uint32_t mFrameNum;
484 nsIntRect mFrameRect;
485 gfx::SurfaceFormat mFormat;
486 uint8_t mPaletteDepth;
489 NewFrameData mNewFrameData;
490 bool mNeedsNewFrame;
491 bool mNeedsToFlushData;
492 bool mInitialized;
493 bool mSizeDecode;
494 bool mInFrame;
495 bool mIsAnimated;
498 } // namespace image
499 } // namespace mozilla
501 #endif // MOZILLA_IMAGELIB_DECODER_H_