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