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_Decoder_h
7 : #define mozilla_image_Decoder_h
8 :
9 : #include "FrameAnimator.h"
10 : #include "RasterImage.h"
11 : #include "mozilla/Maybe.h"
12 : #include "mozilla/NotNull.h"
13 : #include "mozilla/RefPtr.h"
14 : #include "DecodePool.h"
15 : #include "DecoderFlags.h"
16 : #include "Downscaler.h"
17 : #include "ImageMetadata.h"
18 : #include "Orientation.h"
19 : #include "SourceBuffer.h"
20 : #include "StreamingLexer.h"
21 : #include "SurfaceFlags.h"
22 :
23 : namespace mozilla {
24 :
25 : namespace Telemetry {
26 : enum HistogramID : uint32_t;
27 : } // namespace Telemetry
28 :
29 : namespace image {
30 :
31 : struct DecoderFinalStatus final
32 : {
33 33 : DecoderFinalStatus(bool aWasMetadataDecode,
34 : bool aFinished,
35 : bool aHadError,
36 : bool aShouldReportError)
37 33 : : mWasMetadataDecode(aWasMetadataDecode)
38 : , mFinished(aFinished)
39 : , mHadError(aHadError)
40 33 : , mShouldReportError(aShouldReportError)
41 33 : { }
42 :
43 : /// True if this was a metadata decode.
44 : const bool mWasMetadataDecode : 1;
45 :
46 : /// True if this decoder finished, whether successfully or due to failure.
47 : const bool mFinished : 1;
48 :
49 : /// True if this decoder encountered an error.
50 : const bool mHadError : 1;
51 :
52 : /// True if this decoder encountered the kind of error that should be reported
53 : /// to the console.
54 : const bool mShouldReportError : 1;
55 : };
56 :
57 165 : struct DecoderTelemetry final
58 : {
59 33 : DecoderTelemetry(const Maybe<Telemetry::HistogramID>& aSpeedHistogram,
60 : size_t aBytesDecoded,
61 : uint32_t aChunkCount,
62 : TimeDuration aDecodeTime)
63 33 : : mSpeedHistogram(aSpeedHistogram)
64 : , mBytesDecoded(aBytesDecoded)
65 : , mChunkCount(aChunkCount)
66 33 : , mDecodeTime(aDecodeTime)
67 33 : { }
68 :
69 : /// @return our decoder's speed, in KBps.
70 14 : int32_t Speed() const
71 : {
72 14 : return mBytesDecoded / (1024 * mDecodeTime.ToSeconds());
73 : }
74 :
75 : /// @return our decoder's decode time, in microseconds.
76 : int32_t DecodeTimeMicros() { return mDecodeTime.ToMicroseconds(); }
77 :
78 : /// The per-image-format telemetry ID for recording our decoder's speed, or
79 : /// Nothing() if we don't record speed telemetry for this kind of decoder.
80 : const Maybe<Telemetry::HistogramID> mSpeedHistogram;
81 :
82 : /// The number of bytes of input our decoder processed.
83 : const size_t mBytesDecoded;
84 :
85 : /// The number of chunks our decoder's input was divided into.
86 : const uint32_t mChunkCount;
87 :
88 : /// The amount of time our decoder spent inside DoDecode().
89 : const TimeDuration mDecodeTime;
90 : };
91 :
92 : class Decoder
93 : {
94 : public:
95 618 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Decoder)
96 :
97 : explicit Decoder(RasterImage* aImage);
98 :
99 : /**
100 : * Initialize an image decoder. Decoders may not be re-initialized.
101 : *
102 : * @return NS_OK if the decoder could be initialized successfully.
103 : */
104 : nsresult Init();
105 :
106 : /**
107 : * Decodes, reading all data currently available in the SourceBuffer.
108 : *
109 : * If more data is needed and @aOnResume is non-null, Decode() will schedule
110 : * @aOnResume to be called when more data is available.
111 : *
112 : * @return a LexerResult which may indicate:
113 : * - the image has been successfully decoded (TerminalState::SUCCESS), or
114 : * - the image has failed to decode (TerminalState::FAILURE), or
115 : * - the decoder is yielding until it gets more data (Yield::NEED_MORE_DATA), or
116 : * - the decoder is yielding to allow the caller to access intermediate
117 : * output (Yield::OUTPUT_AVAILABLE).
118 : */
119 : LexerResult Decode(IResumable* aOnResume = nullptr);
120 :
121 : /**
122 : * Terminate this decoder in a failure state, just as if the decoder
123 : * implementation had returned TerminalState::FAILURE from DoDecode().
124 : *
125 : * XXX(seth): This method should be removed ASAP; it exists only because
126 : * RasterImage::FinalizeDecoder() requires an actual Decoder object as an
127 : * argument, so we can't simply tell RasterImage a decode failed except via an
128 : * intervening decoder. We'll fix this in bug 1291071.
129 : */
130 : LexerResult TerminateFailure();
131 :
132 : /**
133 : * Given a maximum number of bytes we're willing to decode, @aByteLimit,
134 : * returns true if we should attempt to run this decoder synchronously.
135 : */
136 : bool ShouldSyncDecode(size_t aByteLimit);
137 :
138 : /**
139 : * Gets the invalidation region accumulated by the decoder so far, and clears
140 : * the decoder's invalidation region. This means that each call to
141 : * TakeInvalidRect() returns only the invalidation region accumulated since
142 : * the last call to TakeInvalidRect().
143 : */
144 67 : nsIntRect TakeInvalidRect()
145 : {
146 67 : nsIntRect invalidRect = mInvalidRect;
147 67 : mInvalidRect.SetEmpty();
148 67 : return invalidRect;
149 : }
150 :
151 : /**
152 : * Gets the progress changes accumulated by the decoder so far, and clears
153 : * them. This means that each call to TakeProgress() returns only the changes
154 : * accumulated since the last call to TakeProgress().
155 : */
156 67 : Progress TakeProgress()
157 : {
158 67 : Progress progress = mProgress;
159 67 : mProgress = NoProgress;
160 67 : return progress;
161 : }
162 :
163 : /**
164 : * Returns true if there's any progress to report.
165 : */
166 68 : bool HasProgress() const
167 : {
168 68 : return mProgress != NoProgress || !mInvalidRect.IsEmpty() || mFinishedNewFrame;
169 : }
170 :
171 : /*
172 : * State.
173 : */
174 :
175 : /**
176 : * If we're doing a metadata decode, we only decode the image's headers, which
177 : * is enough to determine the image's intrinsic size. A metadata decode is
178 : * enabled by calling SetMetadataDecode() *before* calling Init().
179 : */
180 33 : void SetMetadataDecode(bool aMetadataDecode)
181 : {
182 33 : MOZ_ASSERT(!mInitialized, "Shouldn't be initialized yet");
183 33 : mMetadataDecode = aMetadataDecode;
184 33 : }
185 329 : bool IsMetadataDecode() const { return mMetadataDecode; }
186 :
187 : /**
188 : * Sets the output size of this decoder. If this is smaller than the intrinsic
189 : * size of the image, we'll downscale it while decoding. For memory usage
190 : * reasons, upscaling is forbidden and will trigger assertions in debug
191 : * builds.
192 : *
193 : * Not calling SetOutputSize() means that we should just decode at the
194 : * intrinsic size, whatever it is.
195 : *
196 : * If SetOutputSize() was called, ExplicitOutputSize() can be used to
197 : * determine the value that was passed to it.
198 : *
199 : * This must be called before Init() is called.
200 : */
201 : void SetOutputSize(const gfx::IntSize& aSize);
202 :
203 : /**
204 : * @return the output size of this decoder. If this is smaller than the
205 : * intrinsic size, then the image will be downscaled during the decoding
206 : * process.
207 : *
208 : * Illegal to call if HasSize() returns false.
209 : */
210 194 : gfx::IntSize OutputSize() const { MOZ_ASSERT(HasSize()); return *mOutputSize; }
211 :
212 : /**
213 : * @return either the size passed to SetOutputSize() or Nothing(), indicating
214 : * that SetOutputSize() was not explicitly called.
215 : */
216 : Maybe<gfx::IntSize> ExplicitOutputSize() const;
217 :
218 : /**
219 : * Set an iterator to the SourceBuffer which will feed data to this decoder.
220 : * This must always be called before calling Init(). (And only before Init().)
221 : *
222 : * XXX(seth): We should eliminate this method and pass a SourceBufferIterator
223 : * to the various decoder constructors instead.
224 : */
225 33 : void SetIterator(SourceBufferIterator&& aIterator)
226 : {
227 33 : MOZ_ASSERT(!mInitialized, "Shouldn't be initialized yet");
228 33 : mIterator.emplace(Move(aIterator));
229 33 : }
230 :
231 : /**
232 : * Should this decoder send partial invalidations?
233 : */
234 1588 : bool ShouldSendPartialInvalidations() const
235 : {
236 1588 : return !(mDecoderFlags & DecoderFlags::IS_REDECODE);
237 : }
238 :
239 : /**
240 : * Should we stop decoding after the first frame?
241 : */
242 1601 : bool IsFirstFrameDecode() const
243 : {
244 1601 : return bool(mDecoderFlags & DecoderFlags::FIRST_FRAME_ONLY);
245 : }
246 :
247 : /**
248 : * @return the number of complete animation frames which have been decoded so
249 : * far, if it has changed since the last call to TakeCompleteFrameCount();
250 : * otherwise, returns Nothing().
251 : */
252 : Maybe<uint32_t> TakeCompleteFrameCount();
253 :
254 : // The number of frames we have, including anything in-progress. Thus, this
255 : // is only 0 if we haven't begun any frames.
256 0 : uint32_t GetFrameCount() { return mFrameCount; }
257 :
258 : // Did we discover that the image we're decoding is animated?
259 48 : bool HasAnimation() const { return mImageMetadata.HasAnimation(); }
260 :
261 : // Error tracking
262 521 : bool HasError() const { return mError; }
263 33 : bool ShouldReportError() const { return mShouldReportError; }
264 :
265 : // Finalize frames
266 0 : void SetFinalizeFrames(bool aFinalize) { mFinalizeFrames = aFinalize; }
267 0 : bool GetFinalizeFrames() const { return mFinalizeFrames; }
268 :
269 : /// Did we finish decoding enough that calling Decode() again would be useless?
270 165 : bool GetDecodeDone() const
271 : {
272 429 : return mReachedTerminalState || mDecodeDone ||
273 334 : (mMetadataDecode && HasSize()) || HasError();
274 : }
275 :
276 : /// Are we in the middle of a frame right now? Used for assertions only.
277 46 : bool InFrame() const { return mInFrame; }
278 :
279 : enum DecodeStyle {
280 : PROGRESSIVE, // produce intermediate frames representing the partial
281 : // state of the image
282 : SEQUENTIAL // decode to final image immediately
283 : };
284 :
285 : /**
286 : * Get or set the DecoderFlags that influence the behavior of this decoder.
287 : */
288 14 : void SetDecoderFlags(DecoderFlags aDecoderFlags)
289 : {
290 14 : MOZ_ASSERT(!mInitialized);
291 14 : mDecoderFlags = aDecoderFlags;
292 14 : }
293 67 : DecoderFlags GetDecoderFlags() const { return mDecoderFlags; }
294 :
295 : /**
296 : * Get or set the SurfaceFlags that select the kind of output this decoder
297 : * will produce.
298 : */
299 14 : void SetSurfaceFlags(SurfaceFlags aSurfaceFlags)
300 : {
301 14 : MOZ_ASSERT(!mInitialized);
302 14 : mSurfaceFlags = aSurfaceFlags;
303 14 : }
304 129 : SurfaceFlags GetSurfaceFlags() const { return mSurfaceFlags; }
305 :
306 : /// @return true if we know the intrinsic size of the image we're decoding.
307 494 : bool HasSize() const { return mImageMetadata.HasSize(); }
308 :
309 : /**
310 : * @return the intrinsic size of the image we're decoding.
311 : *
312 : * Illegal to call if HasSize() returns false.
313 : */
314 196 : gfx::IntSize Size() const
315 : {
316 196 : MOZ_ASSERT(HasSize());
317 196 : return mImageMetadata.GetSize();
318 : }
319 :
320 : /**
321 : * @return an IntRect which covers the entire area of this image at its
322 : * intrinsic size, appropriate for use as a frame rect when the image itself
323 : * does not specify one.
324 : *
325 : * Illegal to call if HasSize() returns false.
326 : */
327 0 : gfx::IntRect FullFrame() const
328 : {
329 0 : return gfx::IntRect(gfx::IntPoint(), Size());
330 : }
331 :
332 : /**
333 : * @return an IntRect which covers the entire area of this image at its size
334 : * after scaling - that is, at its output size.
335 : *
336 : * XXX(seth): This is only used for decoders which are using the old
337 : * Downscaler code instead of SurfacePipe, since the old AllocateFrame() and
338 : * Downscaler APIs required that the frame rect be specified in output space.
339 : * We should remove this once all decoders use SurfacePipe.
340 : *
341 : * Illegal to call if HasSize() returns false.
342 : */
343 0 : gfx::IntRect FullOutputFrame() const
344 : {
345 0 : return gfx::IntRect(gfx::IntPoint(), OutputSize());
346 : }
347 :
348 : /// @return final status information about this decoder. Should be called
349 : /// after we decide we're not going to run the decoder anymore.
350 : DecoderFinalStatus FinalStatus() const;
351 :
352 : /// @return the metadata we collected about this image while decoding.
353 33 : const ImageMetadata& GetImageMetadata() { return mImageMetadata; }
354 :
355 : /// @return performance telemetry we collected while decoding.
356 : DecoderTelemetry Telemetry() const;
357 :
358 : /**
359 : * @return a weak pointer to the image associated with this decoder. Illegal
360 : * to call if this decoder is not associated with an image.
361 : */
362 19 : NotNull<RasterImage*> GetImage() const { return WrapNotNull(mImage.get()); }
363 :
364 : /**
365 : * @return a possibly-null weak pointer to the image associated with this
366 : * decoder. May be called even if this decoder is not associated with an
367 : * image.
368 : */
369 0 : RasterImage* GetImageMaybeNull() const { return mImage.get(); }
370 :
371 48 : RawAccessFrameRef GetCurrentFrameRef()
372 : {
373 : return mCurrentFrame ? mCurrentFrame->RawAccessRef()
374 48 : : RawAccessFrameRef();
375 : }
376 :
377 :
378 : protected:
379 : friend class AutoRecordDecoderTelemetry;
380 : friend class nsICODecoder;
381 : friend class PalettedSurfaceSink;
382 : friend class SurfaceSink;
383 :
384 : virtual ~Decoder();
385 :
386 : /*
387 : * Internal hooks. Decoder implementations may override these and
388 : * only these methods.
389 : *
390 : * BeforeFinishInternal() can be used to detect if decoding is in an
391 : * incomplete state, e.g. due to file truncation, in which case it should
392 : * return a failing nsresult.
393 : */
394 : virtual nsresult InitInternal();
395 : virtual LexerResult DoDecode(SourceBufferIterator& aIterator,
396 : IResumable* aOnResume) = 0;
397 : virtual nsresult BeforeFinishInternal();
398 : virtual nsresult FinishInternal();
399 : virtual nsresult FinishWithErrorInternal();
400 :
401 : /**
402 : * @return the per-image-format telemetry ID for recording this decoder's
403 : * speed, or Nothing() if we don't record speed telemetry for this kind of
404 : * decoder.
405 : */
406 0 : virtual Maybe<Telemetry::HistogramID> SpeedHistogram() const { return Nothing(); }
407 :
408 :
409 : /*
410 : * Progress notifications.
411 : */
412 :
413 : // Called by decoders when they determine the size of the image. Informs
414 : // the image of its size and sends notifications.
415 : void PostSize(int32_t aWidth,
416 : int32_t aHeight,
417 : Orientation aOrientation = Orientation());
418 :
419 : // Called by decoders if they determine that the image has transparency.
420 : //
421 : // This should be fired as early as possible to allow observers to do things
422 : // that affect content, so it's necessarily pessimistic - if there's a
423 : // possibility that the image has transparency, for example because its header
424 : // specifies that it has an alpha channel, we fire PostHasTransparency
425 : // immediately. PostFrameStop's aFrameOpacity argument, on the other hand, is
426 : // only used internally to ImageLib. Because PostFrameStop isn't delivered
427 : // until the entire frame has been decoded, decoders may take into account the
428 : // actual contents of the frame and give a more accurate result.
429 : void PostHasTransparency();
430 :
431 : // Called by decoders if they determine that the image is animated.
432 : //
433 : // @param aTimeout The time for which the first frame should be shown before
434 : // we advance to the next frame.
435 : void PostIsAnimated(FrameTimeout aFirstFrameTimeout);
436 :
437 : // Called by decoders when they end a frame. Informs the image, sends
438 : // notifications, and does internal book-keeping.
439 : // Specify whether this frame is opaque as an optimization.
440 : // For animated images, specify the disposal, blend method and timeout for
441 : // this frame.
442 : void PostFrameStop(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
443 : DisposalMethod aDisposalMethod = DisposalMethod::KEEP,
444 : FrameTimeout aTimeout = FrameTimeout::Forever(),
445 : BlendMethod aBlendMethod = BlendMethod::OVER,
446 : const Maybe<nsIntRect>& aBlendRect = Nothing());
447 :
448 : /**
449 : * Called by the decoders when they have a region to invalidate. We may not
450 : * actually pass these invalidations on right away.
451 : *
452 : * @param aRect The invalidation rect in the coordinate system of the unscaled
453 : * image (that is, the image at its intrinsic size).
454 : * @param aRectAtOutputSize If not Nothing(), the invalidation rect in the
455 : * coordinate system of the scaled image (that is,
456 : * the image at our output size). This must
457 : * be supplied if we're downscaling during decode.
458 : */
459 : void PostInvalidation(const gfx::IntRect& aRect,
460 : const Maybe<gfx::IntRect>& aRectAtOutputSize = Nothing());
461 :
462 : // Called by the decoders when they have successfully decoded the image. This
463 : // may occur as the result of the decoder getting to the appropriate point in
464 : // the stream, or by us calling FinishInternal().
465 : //
466 : // May not be called mid-frame.
467 : //
468 : // For animated images, specify the loop count. -1 means loop forever, 0
469 : // means a single iteration, stopping on the last frame.
470 : void PostDecodeDone(int32_t aLoopCount = 0);
471 :
472 : /**
473 : * Allocates a new frame, making it our current frame if successful.
474 : *
475 : * The @aFrameNum parameter only exists as a sanity check; it's illegal to
476 : * create a new frame anywhere but immediately after the existing frames.
477 : *
478 : * If a non-paletted frame is desired, pass 0 for aPaletteDepth.
479 : */
480 : nsresult AllocateFrame(uint32_t aFrameNum,
481 : const gfx::IntSize& aOutputSize,
482 : const gfx::IntRect& aFrameRect,
483 : gfx::SurfaceFormat aFormat,
484 : uint8_t aPaletteDepth = 0);
485 :
486 : private:
487 : /// Report that an error was encountered while decoding.
488 : void PostError();
489 :
490 : /**
491 : * CompleteDecode() finishes up the decoding process after Decode() determines
492 : * that we're finished. It records final progress and does all the cleanup
493 : * that's possible off-main-thread.
494 : */
495 : void CompleteDecode();
496 :
497 : /// @return the number of complete frames we have. Does not include the
498 : /// current frame if it's unfinished.
499 48 : uint32_t GetCompleteFrameCount()
500 : {
501 48 : if (mFrameCount == 0) {
502 0 : return 0;
503 : }
504 :
505 48 : return mInFrame ? mFrameCount - 1 : mFrameCount;
506 : }
507 :
508 : RawAccessFrameRef AllocateFrameInternal(uint32_t aFrameNum,
509 : const gfx::IntSize& aOutputSize,
510 : const gfx::IntRect& aFrameRect,
511 : gfx::SurfaceFormat aFormat,
512 : uint8_t aPaletteDepth,
513 : imgFrame* aPreviousFrame);
514 :
515 : protected:
516 : Maybe<Downscaler> mDownscaler;
517 :
518 : uint8_t* mImageData; // Pointer to image data in either Cairo or 8bit format
519 : uint32_t mImageDataLength;
520 : uint32_t* mColormap; // Current colormap to be used in Cairo format
521 : uint32_t mColormapSize;
522 :
523 : private:
524 : RefPtr<RasterImage> mImage;
525 : Maybe<SourceBufferIterator> mIterator;
526 : RawAccessFrameRef mCurrentFrame;
527 : ImageMetadata mImageMetadata;
528 : gfx::IntRect mInvalidRect; // Tracks an invalidation region in the current frame.
529 : Maybe<gfx::IntSize> mOutputSize; // The size of our output surface.
530 : Progress mProgress;
531 :
532 : uint32_t mFrameCount; // Number of frames, including anything in-progress
533 : FrameTimeout mLoopLength; // Length of a single loop of this image.
534 : gfx::IntRect mFirstFrameRefreshArea; // The area of the image that needs to
535 : // be invalidated when the animation loops.
536 :
537 : // Telemetry data for this decoder.
538 : TimeDuration mDecodeTime;
539 :
540 : DecoderFlags mDecoderFlags;
541 : SurfaceFlags mSurfaceFlags;
542 :
543 : bool mInitialized : 1;
544 : bool mMetadataDecode : 1;
545 : bool mHaveExplicitOutputSize : 1;
546 : bool mInFrame : 1;
547 : bool mFinishedNewFrame : 1; // True if PostFrameStop() has been called since
548 : // the last call to TakeCompleteFrameCount().
549 : bool mReachedTerminalState : 1;
550 : bool mDecodeDone : 1;
551 : bool mError : 1;
552 : bool mShouldReportError : 1;
553 : bool mFinalizeFrames : 1;
554 : };
555 :
556 : } // namespace image
557 : } // namespace mozilla
558 :
559 : #endif // mozilla_image_Decoder_h
|