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 // Must #include ImageLogging.h before any IPDL-generated files or other files
7 // that #include prlog.h
8 #include "RasterImage.h"
9 
10 #include <stdint.h>
11 
12 #include <algorithm>
13 #include <utility>
14 
15 #include "DecodePool.h"
16 #include "Decoder.h"
17 #include "FrameAnimator.h"
18 #include "GeckoProfiler.h"
19 #include "IDecodingTask.h"
20 #include "ImageLogging.h"
21 #include "ImageRegion.h"
22 #include "Layers.h"
23 #include "LookupResult.h"
24 #include "OrientedImage.h"
25 #include "SourceBuffer.h"
26 #include "SurfaceCache.h"
27 #include "gfx2DGlue.h"
28 #include "gfxContext.h"
29 #include "gfxPlatform.h"
30 #include "mozilla/ClearOnShutdown.h"
31 #include "mozilla/DebugOnly.h"
32 #include "mozilla/Likely.h"
33 #include "mozilla/MemoryReporting.h"
34 #include "mozilla/RefPtr.h"
35 #include "mozilla/SizeOfState.h"
36 #include "mozilla/StaticPrefs_image.h"
37 #include "mozilla/Telemetry.h"
38 #include "mozilla/TimeStamp.h"
39 #include "mozilla/Tuple.h"
40 #include "mozilla/gfx/2D.h"
41 #include "mozilla/gfx/Scale.h"
42 #include "nsComponentManagerUtils.h"
43 #include "nsError.h"
44 #include "nsIConsoleService.h"
45 #include "nsIInputStream.h"
46 #include "nsIScriptError.h"
47 #include "nsISupportsPrimitives.h"
48 #include "nsMemory.h"
49 #include "nsPresContext.h"
50 #include "nsProperties.h"
51 #include "prenv.h"
52 #include "prsystem.h"
53 
54 namespace mozilla {
55 
56 using namespace gfx;
57 using namespace layers;
58 
59 namespace image {
60 
61 using std::ceil;
62 using std::min;
63 
64 #ifndef DEBUG
NS_IMPL_ISUPPORTS(RasterImage,imgIContainer)65 NS_IMPL_ISUPPORTS(RasterImage, imgIContainer)
66 #else
67 NS_IMPL_ISUPPORTS(RasterImage, imgIContainer, imgIContainerDebug)
68 #endif
69 
70 //******************************************************************************
71 RasterImage::RasterImage(nsIURI* aURI /* = nullptr */)
72     : ImageResource(aURI),  // invoke superclass's constructor
73       mSize(0, 0),
74       mLockCount(0),
75       mDecoderType(DecoderType::UNKNOWN),
76       mDecodeCount(0),
77 #ifdef DEBUG
78       mFramesNotified(0),
79 #endif
80       mSourceBuffer(MakeNotNull<SourceBuffer*>()) {
81 }
82 
83 //******************************************************************************
~RasterImage()84 RasterImage::~RasterImage() {
85   // Make sure our SourceBuffer is marked as complete. This will ensure that any
86   // outstanding decoders terminate.
87   if (!mSourceBuffer->IsComplete()) {
88     mSourceBuffer->Complete(NS_ERROR_ABORT);
89   }
90 
91   // Release all frames from the surface cache.
92   SurfaceCache::RemoveImage(ImageKey(this));
93 
94   // Record Telemetry.
95   Telemetry::Accumulate(Telemetry::IMAGE_DECODE_COUNT, mDecodeCount);
96 }
97 
Init(const char * aMimeType,uint32_t aFlags)98 nsresult RasterImage::Init(const char* aMimeType, uint32_t aFlags) {
99   // We don't support re-initialization
100   if (mInitialized) {
101     return NS_ERROR_ILLEGAL_VALUE;
102   }
103 
104   // Not sure an error can happen before init, but be safe
105   if (mError) {
106     return NS_ERROR_FAILURE;
107   }
108 
109   // We want to avoid redecodes for transient images.
110   MOZ_ASSERT_IF(aFlags & INIT_FLAG_TRANSIENT,
111                 !(aFlags & INIT_FLAG_DISCARDABLE));
112 
113   // Store initialization data
114   StoreDiscardable(!!(aFlags & INIT_FLAG_DISCARDABLE));
115   StoreWantFullDecode(!!(aFlags & INIT_FLAG_DECODE_IMMEDIATELY));
116   StoreTransient(!!(aFlags & INIT_FLAG_TRANSIENT));
117   StoreSyncLoad(!!(aFlags & INIT_FLAG_SYNC_LOAD));
118 
119   // Use the MIME type to select a decoder type, and make sure there *is* a
120   // decoder for this MIME type.
121   NS_ENSURE_ARG_POINTER(aMimeType);
122   mDecoderType = DecoderFactory::GetDecoderType(aMimeType);
123   if (mDecoderType == DecoderType::UNKNOWN) {
124     return NS_ERROR_FAILURE;
125   }
126 
127   // Lock this image's surfaces in the SurfaceCache if we're not discardable.
128   if (!LoadDiscardable()) {
129     mLockCount++;
130     SurfaceCache::LockImage(ImageKey(this));
131   }
132 
133   // Mark us as initialized
134   mInitialized = true;
135 
136   return NS_OK;
137 }
138 
139 //******************************************************************************
NS_IMETHODIMP_(void)140 NS_IMETHODIMP_(void)
141 RasterImage::RequestRefresh(const TimeStamp& aTime) {
142   if (HadRecentRefresh(aTime)) {
143     return;
144   }
145 
146   EvaluateAnimation();
147 
148   if (!mAnimating) {
149     return;
150   }
151 
152   RefreshResult res;
153   if (mAnimationState) {
154     MOZ_ASSERT(mFrameAnimator);
155     res = mFrameAnimator->RequestRefresh(*mAnimationState, aTime);
156   }
157 
158 #ifdef DEBUG
159   if (res.mFrameAdvanced) {
160     mFramesNotified++;
161   }
162 #endif
163 
164   // Notify listeners that our frame has actually changed, but do this only
165   // once for all frames that we've now passed (if AdvanceFrame() was called
166   // more than once).
167   if (!res.mDirtyRect.IsEmpty() || res.mFrameAdvanced) {
168     auto dirtyRect = UnorientedIntRect::FromUnknownRect(res.mDirtyRect);
169     NotifyProgress(NoProgress, dirtyRect);
170   }
171 
172   if (res.mAnimationFinished) {
173     StoreAnimationFinished(true);
174     EvaluateAnimation();
175   }
176 }
177 
178 //******************************************************************************
179 NS_IMETHODIMP
GetWidth(int32_t * aWidth)180 RasterImage::GetWidth(int32_t* aWidth) {
181   NS_ENSURE_ARG_POINTER(aWidth);
182 
183   if (mError) {
184     *aWidth = 0;
185     return NS_ERROR_FAILURE;
186   }
187 
188   *aWidth = mSize.width;
189   return NS_OK;
190 }
191 
192 //******************************************************************************
193 NS_IMETHODIMP
GetHeight(int32_t * aHeight)194 RasterImage::GetHeight(int32_t* aHeight) {
195   NS_ENSURE_ARG_POINTER(aHeight);
196 
197   if (mError) {
198     *aHeight = 0;
199     return NS_ERROR_FAILURE;
200   }
201 
202   *aHeight = mSize.height;
203   return NS_OK;
204 }
205 
206 //******************************************************************************
GetNativeSizes(nsTArray<IntSize> & aNativeSizes) const207 nsresult RasterImage::GetNativeSizes(nsTArray<IntSize>& aNativeSizes) const {
208   if (mError) {
209     return NS_ERROR_FAILURE;
210   }
211 
212   aNativeSizes.Clear();
213 
214   if (mNativeSizes.IsEmpty()) {
215     aNativeSizes.AppendElement(mSize.ToUnknownSize());
216   } else {
217     for (const auto& size : mNativeSizes) {
218       aNativeSizes.AppendElement(size.ToUnknownSize());
219     }
220   }
221 
222   return NS_OK;
223 }
224 
225 //******************************************************************************
GetNativeSizesLength() const226 size_t RasterImage::GetNativeSizesLength() const {
227   if (mError || !LoadHasSize()) {
228     return 0;
229   }
230 
231   if (mNativeSizes.IsEmpty()) {
232     return 1;
233   }
234 
235   return mNativeSizes.Length();
236 }
237 
238 //******************************************************************************
239 NS_IMETHODIMP
GetIntrinsicSize(nsSize * aSize)240 RasterImage::GetIntrinsicSize(nsSize* aSize) {
241   if (mError) {
242     return NS_ERROR_FAILURE;
243   }
244 
245   *aSize = nsSize(nsPresContext::CSSPixelsToAppUnits(mSize.width),
246                   nsPresContext::CSSPixelsToAppUnits(mSize.height));
247   return NS_OK;
248 }
249 
250 //******************************************************************************
GetIntrinsicRatio()251 Maybe<AspectRatio> RasterImage::GetIntrinsicRatio() {
252   if (mError) {
253     return Nothing();
254   }
255 
256   return Some(AspectRatio::FromSize(mSize.width, mSize.height));
257 }
258 
NS_IMETHODIMP_(Orientation)259 NS_IMETHODIMP_(Orientation)
260 RasterImage::GetOrientation() { return mOrientation; }
261 
NS_IMETHODIMP_(Resolution)262 NS_IMETHODIMP_(Resolution)
263 RasterImage::GetResolution() { return mResolution; }
264 
265 //******************************************************************************
266 NS_IMETHODIMP
GetType(uint16_t * aType)267 RasterImage::GetType(uint16_t* aType) {
268   NS_ENSURE_ARG_POINTER(aType);
269 
270   *aType = imgIContainer::TYPE_RASTER;
271   return NS_OK;
272 }
273 
274 NS_IMETHODIMP
GetProducerId(uint32_t * aId)275 RasterImage::GetProducerId(uint32_t* aId) {
276   NS_ENSURE_ARG_POINTER(aId);
277 
278   *aId = ImageResource::GetImageProducerId();
279   return NS_OK;
280 }
281 
LookupFrameInternal(const UnorientedIntSize & aSize,uint32_t aFlags,PlaybackType aPlaybackType,bool aMarkUsed)282 LookupResult RasterImage::LookupFrameInternal(const UnorientedIntSize& aSize,
283                                               uint32_t aFlags,
284                                               PlaybackType aPlaybackType,
285                                               bool aMarkUsed) {
286   if (mAnimationState && aPlaybackType == PlaybackType::eAnimated) {
287     MOZ_ASSERT(mFrameAnimator);
288     MOZ_ASSERT(ToSurfaceFlags(aFlags) == DefaultSurfaceFlags(),
289                "Can't composite frames with non-default surface flags");
290     return mFrameAnimator->GetCompositedFrame(*mAnimationState, aMarkUsed);
291   }
292 
293   SurfaceFlags surfaceFlags = ToSurfaceFlags(aFlags);
294 
295   // We don't want any substitution for sync decodes, and substitution would be
296   // illegal when high quality downscaling is disabled, so we use
297   // SurfaceCache::Lookup in this case.
298   if ((aFlags & FLAG_SYNC_DECODE) || !(aFlags & FLAG_HIGH_QUALITY_SCALING)) {
299     return SurfaceCache::Lookup(
300         ImageKey(this),
301         RasterSurfaceKey(aSize.ToUnknownSize(), surfaceFlags,
302                          PlaybackType::eStatic),
303         aMarkUsed);
304   }
305 
306   // We'll return the best match we can find to the requested frame.
307   return SurfaceCache::LookupBestMatch(
308       ImageKey(this),
309       RasterSurfaceKey(aSize.ToUnknownSize(), surfaceFlags,
310                        PlaybackType::eStatic),
311       aMarkUsed);
312 }
313 
LookupFrame(const UnorientedIntSize & aSize,uint32_t aFlags,PlaybackType aPlaybackType,bool aMarkUsed)314 LookupResult RasterImage::LookupFrame(const UnorientedIntSize& aSize,
315                                       uint32_t aFlags,
316                                       PlaybackType aPlaybackType,
317                                       bool aMarkUsed) {
318   MOZ_ASSERT(NS_IsMainThread());
319 
320   // If we're opaque, we don't need to care about premultiplied alpha, because
321   // that can only matter for frames with transparency.
322   if (IsOpaque()) {
323     aFlags &= ~FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
324   }
325 
326   UnorientedIntSize requestedSize =
327       CanDownscaleDuringDecode(aSize, aFlags) ? aSize : ToUnoriented(mSize);
328   if (requestedSize.IsEmpty()) {
329     // Can't decode to a surface of zero size.
330     return LookupResult(MatchType::NOT_FOUND);
331   }
332 
333   LookupResult result =
334       LookupFrameInternal(requestedSize, aFlags, aPlaybackType, aMarkUsed);
335 
336   if (!result && !LoadHasSize()) {
337     // We can't request a decode without knowing our intrinsic size. Give up.
338     return LookupResult(MatchType::NOT_FOUND);
339   }
340 
341   const bool syncDecode = aFlags & FLAG_SYNC_DECODE;
342   const bool avoidRedecode = aFlags & FLAG_AVOID_REDECODE_FOR_SIZE;
343   if (result.Type() == MatchType::NOT_FOUND ||
344       (result.Type() == MatchType::SUBSTITUTE_BECAUSE_NOT_FOUND &&
345        !avoidRedecode) ||
346       (syncDecode && !avoidRedecode && !result)) {
347     // We don't have a copy of this frame, and there's no decoder working on
348     // one. (Or we're sync decoding and the existing decoder hasn't even started
349     // yet.) Trigger decoding so it'll be available next time.
350     MOZ_ASSERT(aPlaybackType != PlaybackType::eAnimated ||
351                    StaticPrefs::image_mem_animated_discardable_AtStartup() ||
352                    !mAnimationState || mAnimationState->KnownFrameCount() < 1,
353                "Animated frames should be locked");
354 
355     // The surface cache may suggest the preferred size we are supposed to
356     // decode at. This should only happen if we accept substitutions.
357     if (!result.SuggestedSize().IsEmpty()) {
358       MOZ_ASSERT(!syncDecode && (aFlags & FLAG_HIGH_QUALITY_SCALING));
359       requestedSize =
360           UnorientedIntSize::FromUnknownSize(result.SuggestedSize());
361     }
362 
363     bool ranSync = false, failed = false;
364     Decode(requestedSize, aFlags, aPlaybackType, ranSync, failed);
365     if (failed) {
366       result.SetFailedToRequestDecode();
367     }
368 
369     // If we can or did sync decode, we should already have the frame.
370     if (ranSync || syncDecode) {
371       result =
372           LookupFrameInternal(requestedSize, aFlags, aPlaybackType, aMarkUsed);
373     }
374   }
375 
376   if (!result) {
377     // We still weren't able to get a frame. Give up.
378     return result;
379   }
380 
381   // Sync decoding guarantees that we got the frame, but if it's owned by an
382   // async decoder that's currently running, the contents of the frame may not
383   // be available yet. Make sure we get everything.
384   if (LoadAllSourceData() && syncDecode) {
385     result.Surface()->WaitUntilFinished();
386   }
387 
388   // If we could have done some decoding in this function we need to check if
389   // that decoding encountered an error and hence aborted the surface. We want
390   // to avoid calling IsAborted if we weren't passed any sync decode flag
391   // because IsAborted acquires the monitor for the imgFrame.
392   if (aFlags & (FLAG_SYNC_DECODE | FLAG_SYNC_DECODE_IF_FAST) &&
393       result.Surface()->IsAborted()) {
394     DrawableSurface tmp = std::move(result.Surface());
395     return result;
396   }
397 
398   return result;
399 }
400 
IsOpaque()401 bool RasterImage::IsOpaque() {
402   if (mError) {
403     return false;
404   }
405 
406   Progress progress = mProgressTracker->GetProgress();
407 
408   // If we haven't yet finished decoding, the safe answer is "not opaque".
409   if (!(progress & FLAG_DECODE_COMPLETE)) {
410     return false;
411   }
412 
413   // Other, we're opaque if FLAG_HAS_TRANSPARENCY is not set.
414   return !(progress & FLAG_HAS_TRANSPARENCY);
415 }
416 
NS_IMETHODIMP_(bool)417 NS_IMETHODIMP_(bool)
418 RasterImage::WillDrawOpaqueNow() {
419   if (!IsOpaque()) {
420     return false;
421   }
422 
423   if (mAnimationState) {
424     if (!StaticPrefs::image_mem_animated_discardable_AtStartup()) {
425       // We never discard frames of animated images.
426       return true;
427     } else {
428       if (mAnimationState->GetCompositedFrameInvalid()) {
429         // We're not going to draw anything at all.
430         return false;
431       }
432     }
433   }
434 
435   // If we are not locked our decoded data could get discard at any time (ie
436   // between the call to this function and when we are asked to draw), so we
437   // have to return false if we are unlocked.
438   if (mLockCount == 0) {
439     return false;
440   }
441 
442   auto size = ToUnoriented(mSize);
443   LookupResult result = SurfaceCache::LookupBestMatch(
444       ImageKey(this),
445       RasterSurfaceKey(size.ToUnknownSize(), DefaultSurfaceFlags(),
446                        PlaybackType::eStatic),
447       /* aMarkUsed = */ false);
448   MatchType matchType = result.Type();
449   if (matchType == MatchType::NOT_FOUND || matchType == MatchType::PENDING ||
450       !result.Surface()->IsFinished()) {
451     return false;
452   }
453 
454   return true;
455 }
456 
OnSurfaceDiscarded(const SurfaceKey & aSurfaceKey)457 void RasterImage::OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) {
458   MOZ_ASSERT(mProgressTracker);
459 
460   bool animatedFramesDiscarded =
461       mAnimationState && aSurfaceKey.Playback() == PlaybackType::eAnimated;
462 
463   nsCOMPtr<nsIEventTarget> eventTarget;
464   if (mProgressTracker) {
465     eventTarget = mProgressTracker->GetEventTarget();
466   } else {
467     eventTarget = do_GetMainThread();
468   }
469 
470   RefPtr<RasterImage> image = this;
471   nsCOMPtr<nsIRunnable> ev =
472       NS_NewRunnableFunction("RasterImage::OnSurfaceDiscarded", [=]() -> void {
473         image->OnSurfaceDiscardedInternal(animatedFramesDiscarded);
474       });
475   eventTarget->Dispatch(ev.forget(), NS_DISPATCH_NORMAL);
476 }
477 
OnSurfaceDiscardedInternal(bool aAnimatedFramesDiscarded)478 void RasterImage::OnSurfaceDiscardedInternal(bool aAnimatedFramesDiscarded) {
479   MOZ_ASSERT(NS_IsMainThread());
480 
481   if (aAnimatedFramesDiscarded && mAnimationState) {
482     MOZ_ASSERT(StaticPrefs::image_mem_animated_discardable_AtStartup());
483     ReleaseImageContainer();
484 
485     auto size = ToUnoriented(mSize);
486     IntRect rect = mAnimationState->UpdateState(this, size.ToUnknownSize());
487 
488     auto dirtyRect = UnorientedIntRect::FromUnknownRect(rect);
489     NotifyProgress(NoProgress, dirtyRect);
490   }
491 
492   if (mProgressTracker) {
493     mProgressTracker->OnDiscard();
494   }
495 }
496 
497 //******************************************************************************
498 NS_IMETHODIMP
GetAnimated(bool * aAnimated)499 RasterImage::GetAnimated(bool* aAnimated) {
500   if (mError) {
501     return NS_ERROR_FAILURE;
502   }
503 
504   NS_ENSURE_ARG_POINTER(aAnimated);
505 
506   // If we have an AnimationState, we can know for sure.
507   if (mAnimationState) {
508     *aAnimated = true;
509     return NS_OK;
510   }
511 
512   // Otherwise, we need to have been decoded to know for sure, since if we were
513   // decoded at least once mAnimationState would have been created for animated
514   // images. This is true even though we check for animation during the
515   // metadata decode, because we may still discover animation only during the
516   // full decode for corrupt images.
517   if (!LoadHasBeenDecoded()) {
518     return NS_ERROR_NOT_AVAILABLE;
519   }
520 
521   // We know for sure
522   *aAnimated = false;
523 
524   return NS_OK;
525 }
526 
527 //******************************************************************************
NS_IMETHODIMP_(int32_t)528 NS_IMETHODIMP_(int32_t)
529 RasterImage::GetFirstFrameDelay() {
530   if (mError) {
531     return -1;
532   }
533 
534   bool animated = false;
535   if (NS_FAILED(GetAnimated(&animated)) || !animated) {
536     return -1;
537   }
538 
539   MOZ_ASSERT(mAnimationState, "Animated images should have an AnimationState");
540   return mAnimationState->FirstFrameTimeout().AsEncodedValueDeprecated();
541 }
542 
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)543 NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
544 RasterImage::GetFrame(uint32_t aWhichFrame, uint32_t aFlags) {
545   return GetFrameAtSize(mSize.ToUnknownSize(), aWhichFrame, aFlags);
546 }
547 
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)548 NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
549 RasterImage::GetFrameAtSize(const IntSize& aSize, uint32_t aWhichFrame,
550                             uint32_t aFlags) {
551   AutoProfilerImagePaintMarker PROFILER_RAII(this);
552 #ifdef DEBUG
553   NotifyDrawingObservers();
554 #endif
555 
556   auto result =
557       GetFrameInternal(aSize, Nothing(), Nothing(), aWhichFrame, aFlags);
558   return mozilla::Get<2>(result).forget();
559 }
560 
561 Tuple<ImgDrawResult, IntSize, RefPtr<SourceSurface>>
GetFrameInternal(const IntSize & aSize,const Maybe<SVGImageContext> & aSVGContext,const Maybe<ImageIntRegion> & aRegion,uint32_t aWhichFrame,uint32_t aFlags)562 RasterImage::GetFrameInternal(const IntSize& aSize,
563                               const Maybe<SVGImageContext>& aSVGContext,
564                               const Maybe<ImageIntRegion>& aRegion,
565                               uint32_t aWhichFrame, uint32_t aFlags) {
566   MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
567 
568   auto size = OrientedIntSize::FromUnknownSize(aSize);
569 
570   if (aSize.IsEmpty() || aWhichFrame > FRAME_MAX_VALUE) {
571     return MakeTuple(ImgDrawResult::BAD_ARGS, aSize, RefPtr<SourceSurface>());
572   }
573 
574   if (mError) {
575     return MakeTuple(ImgDrawResult::BAD_IMAGE, aSize, RefPtr<SourceSurface>());
576   }
577 
578   // Get the frame. If it's not there, it's probably the caller's fault for
579   // not waiting for the data to be loaded from the network or not passing
580   // FLAG_SYNC_DECODE.
581   LookupResult result =
582       LookupFrame(ToUnoriented(size), aFlags, ToPlaybackType(aWhichFrame),
583                   /* aMarkUsed = */ true);
584   auto resultSuggestedSize =
585       UnorientedIntSize::FromUnknownSize(result.SuggestedSize());
586 
587   // The surface cache may have suggested we use a different size than the
588   // given size in the future. This may or may not be accompanied by an
589   // actual surface, depending on what it has in its cache.
590   OrientedIntSize suggestedSize = ToOriented(resultSuggestedSize);
591   if (suggestedSize.IsEmpty()) {
592     suggestedSize = size;
593   }
594   MOZ_ASSERT_IF(result.Type() == MatchType::SUBSTITUTE_BECAUSE_BEST,
595                 suggestedSize != size);
596 
597   if (!result) {
598     // The OS threw this frame away and we couldn't redecode it.
599     return MakeTuple(ImgDrawResult::TEMPORARY_ERROR,
600                      suggestedSize.ToUnknownSize(), RefPtr<SourceSurface>());
601   }
602 
603   RefPtr<SourceSurface> surface = result.Surface()->GetSourceSurface();
604 
605   // If this RasterImage requires orientation, we must return a newly created
606   // surface with the oriented image instead of returning the frame's surface
607   // directly.
608   surface = OrientedImage::OrientSurface(mOrientation, surface);
609 
610   if (!result.Surface()->IsFinished()) {
611     return MakeTuple(ImgDrawResult::INCOMPLETE, suggestedSize.ToUnknownSize(),
612                      std::move(surface));
613   }
614 
615   return MakeTuple(ImgDrawResult::SUCCESS, suggestedSize.ToUnknownSize(),
616                    std::move(surface));
617 }
618 
GetImageContainerSize(LayerManager * aManager,const IntSize & aRequestedSize,uint32_t aFlags)619 Tuple<ImgDrawResult, IntSize> RasterImage::GetImageContainerSize(
620     LayerManager* aManager, const IntSize& aRequestedSize, uint32_t aFlags) {
621   if (!LoadHasSize()) {
622     return MakeTuple(ImgDrawResult::NOT_READY, IntSize(0, 0));
623   }
624 
625   if (aRequestedSize.IsEmpty()) {
626     return MakeTuple(ImgDrawResult::BAD_ARGS, IntSize(0, 0));
627   }
628 
629   // We check the minimum size because while we support downscaling, we do not
630   // support upscaling. If aRequestedSize > mSize, we will never give a larger
631   // surface than mSize. If mSize > aRequestedSize, and mSize > maxTextureSize,
632   // we still want to use image containers if aRequestedSize <= maxTextureSize.
633   int32_t maxTextureSize = aManager->GetMaxTextureSize();
634   if (min(mSize.width, aRequestedSize.width) > maxTextureSize ||
635       min(mSize.height, aRequestedSize.height) > maxTextureSize) {
636     return MakeTuple(ImgDrawResult::NOT_SUPPORTED, IntSize(0, 0));
637   }
638 
639   auto requestedSize = OrientedIntSize::FromUnknownSize(aRequestedSize);
640   if (!CanDownscaleDuringDecode(ToUnoriented(requestedSize), aFlags)) {
641     return MakeTuple(ImgDrawResult::SUCCESS, mSize.ToUnknownSize());
642   }
643 
644   return MakeTuple(ImgDrawResult::SUCCESS, aRequestedSize);
645 }
646 
NS_IMETHODIMP_(bool)647 NS_IMETHODIMP_(bool)
648 RasterImage::IsImageContainerAvailable(LayerManager* aManager,
649                                        uint32_t aFlags) {
650   return IsImageContainerAvailableAtSize(aManager, mSize.ToUnknownSize(),
651                                          aFlags);
652 }
653 
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)654 NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
655 RasterImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags) {
656   // Strip out unsupported flags for raster images.
657   uint32_t flags = aFlags & ~(FLAG_RECORD_BLOB);
658 
659   RefPtr<ImageContainer> container;
660   ImgDrawResult drawResult =
661       GetImageContainerImpl(aManager, mSize.ToUnknownSize(), Nothing(),
662                             Nothing(), flags, getter_AddRefs(container));
663 
664   // We silence the unused warning here because anything that needs the draw
665   // result should be using GetImageContainerAtSize, not GetImageContainer.
666   (void)drawResult;
667   return container.forget();
668 }
669 
NS_IMETHODIMP_(bool)670 NS_IMETHODIMP_(bool)
671 RasterImage::IsImageContainerAvailableAtSize(LayerManager* aManager,
672                                              const IntSize& aRequestedSize,
673                                              uint32_t aFlags) {
674   // We check the minimum size because while we support downscaling, we do not
675   // support upscaling. If aRequestedSize > mSize, we will never give a larger
676   // surface than mSize. If mSize > aRequestedSize, and mSize > maxTextureSize,
677   // we still want to use image containers if aRequestedSize <= maxTextureSize.
678   int32_t maxTextureSize = aManager->GetMaxTextureSize();
679   if (!LoadHasSize() || aRequestedSize.IsEmpty() ||
680       min(mSize.width, aRequestedSize.width) > maxTextureSize ||
681       min(mSize.height, aRequestedSize.height) > maxTextureSize) {
682     return false;
683   }
684 
685   return true;
686 }
687 
NS_IMETHODIMP_(ImgDrawResult)688 NS_IMETHODIMP_(ImgDrawResult)
689 RasterImage::GetImageContainerAtSize(layers::LayerManager* aManager,
690                                      const gfx::IntSize& aSize,
691                                      const Maybe<SVGImageContext>& aSVGContext,
692                                      const Maybe<ImageIntRegion>& aRegion,
693                                      uint32_t aFlags,
694                                      layers::ImageContainer** aOutContainer) {
695   // We do not pass in the given SVG context because in theory it could differ
696   // between calls, but actually have no impact on the actual contents of the
697   // image container.
698   return GetImageContainerImpl(aManager, aSize, Nothing(), Nothing(), aFlags,
699                                aOutContainer);
700 }
701 
SizeOfSourceWithComputedFallback(SizeOfState & aState) const702 size_t RasterImage::SizeOfSourceWithComputedFallback(
703     SizeOfState& aState) const {
704   return mSourceBuffer->SizeOfIncludingThisWithComputedFallback(
705       aState.mMallocSizeOf);
706 }
707 
CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter> & aCounters,MallocSizeOf aMallocSizeOf) const708 void RasterImage::CollectSizeOfSurfaces(
709     nsTArray<SurfaceMemoryCounter>& aCounters,
710     MallocSizeOf aMallocSizeOf) const {
711   SurfaceCache::CollectSizeOfSurfaces(ImageKey(this), aCounters, aMallocSizeOf);
712   ImageResource::CollectSizeOfSurfaces(aCounters, aMallocSizeOf);
713 }
714 
SetMetadata(const ImageMetadata & aMetadata,bool aFromMetadataDecode)715 bool RasterImage::SetMetadata(const ImageMetadata& aMetadata,
716                               bool aFromMetadataDecode) {
717   MOZ_ASSERT(NS_IsMainThread());
718 
719   if (mError) {
720     return true;
721   }
722 
723   mResolution = aMetadata.GetResolution();
724 
725   if (aMetadata.HasSize()) {
726     auto metadataSize = UnorientedIntSize::FromUnknownSize(aMetadata.GetSize());
727     if (metadataSize.width < 0 || metadataSize.height < 0) {
728       NS_WARNING("Image has negative intrinsic size");
729       DoError();
730       return true;
731     }
732 
733     MOZ_ASSERT(aMetadata.HasOrientation());
734     Orientation orientation = aMetadata.GetOrientation();
735 
736     // If we already have a size, check the new size against the old one.
737     if (LoadHasSize() &&
738         (metadataSize != ToUnoriented(mSize) || orientation != mOrientation)) {
739       NS_WARNING(
740           "Image changed size or orientation on redecode! "
741           "This should not happen!");
742       DoError();
743       return true;
744     }
745 
746     // Set the size and flag that we have it.
747     mOrientation = orientation;
748     mSize = ToOriented(metadataSize);
749     mNativeSizes.Clear();
750     for (const auto& nativeSize : aMetadata.GetNativeSizes()) {
751       mNativeSizes.AppendElement(
752           ToOriented(UnorientedIntSize::FromUnknownSize(nativeSize)));
753     }
754     StoreHasSize(true);
755   }
756 
757   if (LoadHasSize() && aMetadata.HasAnimation() && !mAnimationState) {
758     // We're becoming animated, so initialize animation stuff.
759     mAnimationState.emplace(mAnimationMode);
760     mFrameAnimator =
761         MakeUnique<FrameAnimator>(this, ToUnoriented(mSize).ToUnknownSize());
762 
763     if (!StaticPrefs::image_mem_animated_discardable_AtStartup()) {
764       // We don't support discarding animated images (See bug 414259).
765       // Lock the image and throw away the key.
766       LockImage();
767     }
768 
769     if (!aFromMetadataDecode) {
770       // The metadata decode reported that this image isn't animated, but we
771       // discovered that it actually was during the full decode. This is a
772       // rare failure that only occurs for corrupt images. To recover, we need
773       // to discard all existing surfaces and redecode.
774       return false;
775     }
776   }
777 
778   if (mAnimationState) {
779     mAnimationState->SetLoopCount(aMetadata.GetLoopCount());
780     mAnimationState->SetFirstFrameTimeout(aMetadata.GetFirstFrameTimeout());
781 
782     if (aMetadata.HasLoopLength()) {
783       mAnimationState->SetLoopLength(aMetadata.GetLoopLength());
784     }
785     if (aMetadata.HasFirstFrameRefreshArea()) {
786       mAnimationState->SetFirstFrameRefreshArea(
787           aMetadata.GetFirstFrameRefreshArea());
788     }
789   }
790 
791   if (aMetadata.HasHotspot()) {
792     // NOTE(heycam): We shouldn't have any image formats that support both
793     // orientation and hotspots, so we assert that rather than add code
794     // to orient the hotspot point correctly.
795     MOZ_ASSERT(mOrientation.IsIdentity(), "Would need to orient hotspot point");
796 
797     auto hotspot = aMetadata.GetHotspot();
798     mHotspot.x = std::max(std::min(hotspot.x, mSize.width - 1), 0);
799     mHotspot.y = std::max(std::min(hotspot.y, mSize.height - 1), 0);
800   }
801 
802   return true;
803 }
804 
805 NS_IMETHODIMP
SetAnimationMode(uint16_t aAnimationMode)806 RasterImage::SetAnimationMode(uint16_t aAnimationMode) {
807   if (mAnimationState) {
808     mAnimationState->SetAnimationMode(aAnimationMode);
809   }
810   return SetAnimationModeInternal(aAnimationMode);
811 }
812 
813 //******************************************************************************
814 
StartAnimation()815 nsresult RasterImage::StartAnimation() {
816   if (mError) {
817     return NS_ERROR_FAILURE;
818   }
819 
820   MOZ_ASSERT(ShouldAnimate(), "Should not animate!");
821 
822   // If we're not ready to animate, then set mPendingAnimation, which will cause
823   // us to start animating if and when we do become ready.
824   StorePendingAnimation(!mAnimationState ||
825                         mAnimationState->KnownFrameCount() < 1);
826   if (LoadPendingAnimation()) {
827     return NS_OK;
828   }
829 
830   // Don't bother to animate if we're displaying the first frame forever.
831   if (mAnimationState->GetCurrentAnimationFrameIndex() == 0 &&
832       mAnimationState->FirstFrameTimeout() == FrameTimeout::Forever()) {
833     StoreAnimationFinished(true);
834     return NS_ERROR_ABORT;
835   }
836 
837   // We need to set the time that this initial frame was first displayed, as
838   // this is used in AdvanceFrame().
839   mAnimationState->InitAnimationFrameTimeIfNecessary();
840 
841   return NS_OK;
842 }
843 
844 //******************************************************************************
StopAnimation()845 nsresult RasterImage::StopAnimation() {
846   MOZ_ASSERT(mAnimating, "Should be animating!");
847 
848   nsresult rv = NS_OK;
849   if (mError) {
850     rv = NS_ERROR_FAILURE;
851   } else {
852     mAnimationState->SetAnimationFrameTime(TimeStamp());
853   }
854 
855   mAnimating = false;
856   return rv;
857 }
858 
859 //******************************************************************************
860 NS_IMETHODIMP
ResetAnimation()861 RasterImage::ResetAnimation() {
862   if (mError) {
863     return NS_ERROR_FAILURE;
864   }
865 
866   StorePendingAnimation(false);
867 
868   if (mAnimationMode == kDontAnimMode || !mAnimationState ||
869       mAnimationState->GetCurrentAnimationFrameIndex() == 0) {
870     return NS_OK;
871   }
872 
873   StoreAnimationFinished(false);
874 
875   if (mAnimating) {
876     StopAnimation();
877   }
878 
879   MOZ_ASSERT(mAnimationState, "Should have AnimationState");
880   MOZ_ASSERT(mFrameAnimator, "Should have FrameAnimator");
881   mFrameAnimator->ResetAnimation(*mAnimationState);
882 
883   IntRect area = mAnimationState->FirstFrameRefreshArea();
884   NotifyProgress(NoProgress, UnorientedIntRect::FromUnknownRect(area));
885 
886   // Start the animation again. It may not have been running before, if
887   // mAnimationFinished was true before entering this function.
888   EvaluateAnimation();
889 
890   return NS_OK;
891 }
892 
893 //******************************************************************************
NS_IMETHODIMP_(void)894 NS_IMETHODIMP_(void)
895 RasterImage::SetAnimationStartTime(const TimeStamp& aTime) {
896   if (mError || mAnimationMode == kDontAnimMode || mAnimating ||
897       !mAnimationState) {
898     return;
899   }
900 
901   mAnimationState->SetAnimationFrameTime(aTime);
902 }
903 
NS_IMETHODIMP_(float)904 NS_IMETHODIMP_(float)
905 RasterImage::GetFrameIndex(uint32_t aWhichFrame) {
906   MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE, "Invalid argument");
907   return (aWhichFrame == FRAME_FIRST || !mAnimationState)
908              ? 0.0f
909              : mAnimationState->GetCurrentAnimationFrameIndex();
910 }
911 
NS_IMETHODIMP_(IntRect)912 NS_IMETHODIMP_(IntRect)
913 RasterImage::GetImageSpaceInvalidationRect(const IntRect& aRect) {
914   // Note that we do not transform aRect into an UnorientedIntRect, since
915   // RasterImage::NotifyProgress notifies all consumers of the image using
916   // OrientedIntRect values.  (This is unlike OrientedImage, which notifies
917   // using inner image coordinates.)
918   return aRect;
919 }
920 
OnImageDataComplete(nsIRequest *,nsISupports *,nsresult aStatus,bool aLastPart)921 nsresult RasterImage::OnImageDataComplete(nsIRequest*, nsISupports*,
922                                           nsresult aStatus, bool aLastPart) {
923   MOZ_ASSERT(NS_IsMainThread());
924 
925   // Record that we have all the data we're going to get now.
926   StoreAllSourceData(true);
927 
928   // Let decoders know that there won't be any more data coming.
929   mSourceBuffer->Complete(aStatus);
930 
931   // Allow a synchronous metadata decode if mSyncLoad was set, or if we're
932   // running on a single thread (in which case waiting for the async metadata
933   // decoder could delay this image's load event quite a bit), or if this image
934   // is transient.
935   bool canSyncDecodeMetadata =
936       LoadSyncLoad() || LoadTransient() || DecodePool::NumberOfCores() < 2;
937 
938   if (canSyncDecodeMetadata && !LoadHasSize()) {
939     // We're loading this image synchronously, so it needs to be usable after
940     // this call returns.  Since we haven't gotten our size yet, we need to do a
941     // synchronous metadata decode here.
942     DecodeMetadata(FLAG_SYNC_DECODE);
943   }
944 
945   // Determine our final status, giving precedence to Necko failure codes. We
946   // check after running the metadata decode in case it triggered an error.
947   nsresult finalStatus = mError ? NS_ERROR_FAILURE : NS_OK;
948   if (NS_FAILED(aStatus)) {
949     finalStatus = aStatus;
950   }
951 
952   // If loading failed, report an error.
953   if (NS_FAILED(finalStatus)) {
954     DoError();
955   }
956 
957   Progress loadProgress = LoadCompleteProgress(aLastPart, mError, finalStatus);
958 
959   if (!LoadHasSize() && !mError) {
960     // We don't have our size yet, so we'll fire the load event in SetSize().
961     MOZ_ASSERT(!canSyncDecodeMetadata,
962                "Firing load async after metadata sync decode?");
963     mLoadProgress = Some(loadProgress);
964     return finalStatus;
965   }
966 
967   NotifyForLoadEvent(loadProgress);
968 
969   return finalStatus;
970 }
971 
NotifyForLoadEvent(Progress aProgress)972 void RasterImage::NotifyForLoadEvent(Progress aProgress) {
973   MOZ_ASSERT(LoadHasSize() || mError,
974              "Need to know size before firing load event");
975   MOZ_ASSERT(
976       !LoadHasSize() || (mProgressTracker->GetProgress() & FLAG_SIZE_AVAILABLE),
977       "Should have notified that the size is available if we have it");
978 
979   // If we encountered an error, make sure we notify for that as well.
980   if (mError) {
981     aProgress |= FLAG_HAS_ERROR;
982   }
983 
984   // Notify our listeners, which will fire this image's load event.
985   NotifyProgress(aProgress);
986 }
987 
OnImageDataAvailable(nsIRequest *,nsISupports *,nsIInputStream * aInputStream,uint64_t,uint32_t aCount)988 nsresult RasterImage::OnImageDataAvailable(nsIRequest*, nsISupports*,
989                                            nsIInputStream* aInputStream,
990                                            uint64_t, uint32_t aCount) {
991   nsresult rv = mSourceBuffer->AppendFromInputStream(aInputStream, aCount);
992   if (NS_SUCCEEDED(rv) && !LoadSomeSourceData()) {
993     StoreSomeSourceData(true);
994     if (!LoadSyncLoad()) {
995       // Create an async metadata decoder and verify we succeed in doing so.
996       rv = DecodeMetadata(DECODE_FLAGS_DEFAULT);
997     }
998   }
999 
1000   if (NS_FAILED(rv)) {
1001     DoError();
1002   }
1003   return rv;
1004 }
1005 
SetSourceSizeHint(uint32_t aSizeHint)1006 nsresult RasterImage::SetSourceSizeHint(uint32_t aSizeHint) {
1007   if (aSizeHint == 0) {
1008     return NS_OK;
1009   }
1010 
1011   nsresult rv = mSourceBuffer->ExpectLength(aSizeHint);
1012   if (rv == NS_ERROR_OUT_OF_MEMORY) {
1013     // Flush memory, try to get some back, and try again.
1014     rv = nsMemory::HeapMinimize(true);
1015     if (NS_SUCCEEDED(rv)) {
1016       rv = mSourceBuffer->ExpectLength(aSizeHint);
1017     }
1018   }
1019 
1020   return rv;
1021 }
1022 
GetHotspotX(int32_t * aX)1023 nsresult RasterImage::GetHotspotX(int32_t* aX) {
1024   *aX = mHotspot.x;
1025   return NS_OK;
1026 }
1027 
GetHotspotY(int32_t * aY)1028 nsresult RasterImage::GetHotspotY(int32_t* aY) {
1029   *aY = mHotspot.y;
1030   return NS_OK;
1031 }
1032 
Discard()1033 void RasterImage::Discard() {
1034   MOZ_ASSERT(NS_IsMainThread());
1035   MOZ_ASSERT(CanDiscard(), "Asked to discard but can't");
1036   MOZ_ASSERT(!mAnimationState ||
1037                  StaticPrefs::image_mem_animated_discardable_AtStartup(),
1038              "Asked to discard for animated image");
1039 
1040   // Delete all the decoded frames.
1041   SurfaceCache::RemoveImage(ImageKey(this));
1042 
1043   if (mAnimationState) {
1044     ReleaseImageContainer();
1045 
1046     auto size = ToUnoriented(mSize);
1047     IntRect rect = mAnimationState->UpdateState(this, size.ToUnknownSize());
1048 
1049     auto dirtyRect = UnorientedIntRect::FromUnknownRect(rect);
1050     NotifyProgress(NoProgress, dirtyRect);
1051   }
1052 
1053   // Notify that we discarded.
1054   if (mProgressTracker) {
1055     mProgressTracker->OnDiscard();
1056   }
1057 }
1058 
CanDiscard()1059 bool RasterImage::CanDiscard() {
1060   return LoadAllSourceData() &&
1061          // Can discard animated images if the pref is set
1062          (!mAnimationState ||
1063           StaticPrefs::image_mem_animated_discardable_AtStartup());
1064 }
1065 
1066 NS_IMETHODIMP
StartDecoding(uint32_t aFlags,uint32_t aWhichFrame)1067 RasterImage::StartDecoding(uint32_t aFlags, uint32_t aWhichFrame) {
1068   if (mError) {
1069     return NS_ERROR_FAILURE;
1070   }
1071 
1072   if (!LoadHasSize()) {
1073     StoreWantFullDecode(true);
1074     return NS_OK;
1075   }
1076 
1077   uint32_t flags = (aFlags & FLAG_ASYNC_NOTIFY) | FLAG_SYNC_DECODE_IF_FAST |
1078                    FLAG_HIGH_QUALITY_SCALING;
1079   return RequestDecodeForSize(mSize.ToUnknownSize(), flags, aWhichFrame);
1080 }
1081 
StartDecodingWithResult(uint32_t aFlags,uint32_t aWhichFrame)1082 bool RasterImage::StartDecodingWithResult(uint32_t aFlags,
1083                                           uint32_t aWhichFrame) {
1084   if (mError) {
1085     return false;
1086   }
1087 
1088   if (!LoadHasSize()) {
1089     StoreWantFullDecode(true);
1090     return false;
1091   }
1092 
1093   uint32_t flags = (aFlags & FLAG_ASYNC_NOTIFY) | FLAG_SYNC_DECODE_IF_FAST |
1094                    FLAG_HIGH_QUALITY_SCALING;
1095   LookupResult result =
1096       RequestDecodeForSizeInternal(ToUnoriented(mSize), flags, aWhichFrame);
1097   DrawableSurface surface = std::move(result.Surface());
1098   return surface && surface->IsFinished();
1099 }
1100 
RequestDecodeWithResult(uint32_t aFlags,uint32_t aWhichFrame)1101 imgIContainer::DecodeResult RasterImage::RequestDecodeWithResult(
1102     uint32_t aFlags, uint32_t aWhichFrame) {
1103   MOZ_ASSERT(NS_IsMainThread());
1104 
1105   if (mError) {
1106     return imgIContainer::DECODE_REQUEST_FAILED;
1107   }
1108 
1109   uint32_t flags = aFlags | FLAG_ASYNC_NOTIFY;
1110   LookupResult result =
1111       RequestDecodeForSizeInternal(ToUnoriented(mSize), flags, aWhichFrame);
1112   DrawableSurface surface = std::move(result.Surface());
1113   if (surface && surface->IsFinished()) {
1114     return imgIContainer::DECODE_SURFACE_AVAILABLE;
1115   }
1116   if (result.GetFailedToRequestDecode()) {
1117     return imgIContainer::DECODE_REQUEST_FAILED;
1118   }
1119   return imgIContainer::DECODE_REQUESTED;
1120 }
1121 
1122 NS_IMETHODIMP
RequestDecodeForSize(const IntSize & aSize,uint32_t aFlags,uint32_t aWhichFrame)1123 RasterImage::RequestDecodeForSize(const IntSize& aSize, uint32_t aFlags,
1124                                   uint32_t aWhichFrame) {
1125   MOZ_ASSERT(NS_IsMainThread());
1126 
1127   if (mError) {
1128     return NS_ERROR_FAILURE;
1129   }
1130 
1131   RequestDecodeForSizeInternal(
1132       ToUnoriented(OrientedIntSize::FromUnknownSize(aSize)), aFlags,
1133       aWhichFrame);
1134 
1135   return NS_OK;
1136 }
1137 
RequestDecodeForSizeInternal(const UnorientedIntSize & aSize,uint32_t aFlags,uint32_t aWhichFrame)1138 LookupResult RasterImage::RequestDecodeForSizeInternal(
1139     const UnorientedIntSize& aSize, uint32_t aFlags, uint32_t aWhichFrame) {
1140   MOZ_ASSERT(NS_IsMainThread());
1141 
1142   if (aWhichFrame > FRAME_MAX_VALUE) {
1143     return LookupResult(MatchType::NOT_FOUND);
1144   }
1145 
1146   if (mError) {
1147     LookupResult result = LookupResult(MatchType::NOT_FOUND);
1148     result.SetFailedToRequestDecode();
1149     return result;
1150   }
1151 
1152   if (!LoadHasSize()) {
1153     StoreWantFullDecode(true);
1154     return LookupResult(MatchType::NOT_FOUND);
1155   }
1156 
1157   // Decide whether to sync decode images we can decode quickly. Here we are
1158   // explicitly trading off flashing for responsiveness in the case that we're
1159   // redecoding an image (see bug 845147).
1160   bool shouldSyncDecodeIfFast =
1161       !LoadHasBeenDecoded() && (aFlags & FLAG_SYNC_DECODE_IF_FAST);
1162 
1163   uint32_t flags =
1164       shouldSyncDecodeIfFast ? aFlags : aFlags & ~FLAG_SYNC_DECODE_IF_FAST;
1165 
1166   // Perform a frame lookup, which will implicitly start decoding if needed.
1167   return LookupFrame(aSize, flags, ToPlaybackType(aWhichFrame),
1168                      /* aMarkUsed = */ false);
1169 }
1170 
LaunchDecodingTask(IDecodingTask * aTask,RasterImage * aImage,uint32_t aFlags,bool aHaveSourceData)1171 static bool LaunchDecodingTask(IDecodingTask* aTask, RasterImage* aImage,
1172                                uint32_t aFlags, bool aHaveSourceData) {
1173   if (aHaveSourceData) {
1174     nsCString uri(aImage->GetURIString());
1175 
1176     // If we have all the data, we can sync decode if requested.
1177     if (aFlags & imgIContainer::FLAG_SYNC_DECODE) {
1178       DecodePool::Singleton()->SyncRunIfPossible(aTask, uri);
1179       return true;
1180     }
1181 
1182     if (aFlags & imgIContainer::FLAG_SYNC_DECODE_IF_FAST) {
1183       return DecodePool::Singleton()->SyncRunIfPreferred(aTask, uri);
1184     }
1185   }
1186 
1187   // Perform an async decode. We also take this path if we don't have all the
1188   // source data yet, since sync decoding is impossible in that situation.
1189   DecodePool::Singleton()->AsyncRun(aTask);
1190   return false;
1191 }
1192 
Decode(const UnorientedIntSize & aSize,uint32_t aFlags,PlaybackType aPlaybackType,bool & aOutRanSync,bool & aOutFailed)1193 void RasterImage::Decode(const UnorientedIntSize& aSize, uint32_t aFlags,
1194                          PlaybackType aPlaybackType, bool& aOutRanSync,
1195                          bool& aOutFailed) {
1196   MOZ_ASSERT(NS_IsMainThread());
1197 
1198   if (mError) {
1199     aOutFailed = true;
1200     return;
1201   }
1202 
1203   // If we don't have a size yet, we can't do any other decoding.
1204   if (!LoadHasSize()) {
1205     StoreWantFullDecode(true);
1206     return;
1207   }
1208 
1209   // We're about to decode again, which may mean that some of the previous sizes
1210   // we've decoded at aren't useful anymore. We can allow them to expire from
1211   // the cache by unlocking them here. When the decode finishes, it will send an
1212   // invalidation that will cause all instances of this image to redraw. If this
1213   // image is locked, any surfaces that are still useful will become locked
1214   // again when LookupFrame touches them, and the remainder will eventually
1215   // expire.
1216   SurfaceCache::UnlockEntries(ImageKey(this));
1217 
1218   // Determine which flags we need to decode this image with.
1219   DecoderFlags decoderFlags = DefaultDecoderFlags();
1220   if (aFlags & FLAG_ASYNC_NOTIFY) {
1221     decoderFlags |= DecoderFlags::ASYNC_NOTIFY;
1222   }
1223   if (LoadTransient()) {
1224     decoderFlags |= DecoderFlags::IMAGE_IS_TRANSIENT;
1225   }
1226   if (LoadHasBeenDecoded()) {
1227     decoderFlags |= DecoderFlags::IS_REDECODE;
1228   }
1229   if ((aFlags & FLAG_SYNC_DECODE) || !(aFlags & FLAG_HIGH_QUALITY_SCALING)) {
1230     // Used SurfaceCache::Lookup instead of SurfaceCache::LookupBestMatch. That
1231     // means the caller can handle a differently sized surface to be returned
1232     // at any point.
1233     decoderFlags |= DecoderFlags::CANNOT_SUBSTITUTE;
1234   }
1235 
1236   SurfaceFlags surfaceFlags = ToSurfaceFlags(aFlags);
1237   if (IsOpaque()) {
1238     // If there's no transparency, it doesn't matter whether we premultiply
1239     // alpha or not.
1240     surfaceFlags &= ~SurfaceFlags::NO_PREMULTIPLY_ALPHA;
1241   }
1242 
1243   // Create a decoder.
1244   RefPtr<IDecodingTask> task;
1245   nsresult rv;
1246   bool animated = mAnimationState && aPlaybackType == PlaybackType::eAnimated;
1247   if (animated) {
1248     size_t currentFrame = mAnimationState->GetCurrentAnimationFrameIndex();
1249     rv = DecoderFactory::CreateAnimationDecoder(
1250         mDecoderType, WrapNotNull(this), mSourceBuffer,
1251         ToUnoriented(mSize).ToUnknownSize(), decoderFlags, surfaceFlags,
1252         currentFrame, getter_AddRefs(task));
1253   } else {
1254     rv = DecoderFactory::CreateDecoder(
1255         mDecoderType, WrapNotNull(this), mSourceBuffer,
1256         ToUnoriented(mSize).ToUnknownSize(), aSize.ToUnknownSize(),
1257         decoderFlags, surfaceFlags, getter_AddRefs(task));
1258   }
1259 
1260   if (rv == NS_ERROR_ALREADY_INITIALIZED) {
1261     // We raced with an already pending decoder, and it finished before we
1262     // managed to insert the new decoder. Pretend we did a sync call to make
1263     // the caller lookup in the surface cache again.
1264     MOZ_ASSERT(!task);
1265     aOutRanSync = true;
1266     return;
1267   }
1268 
1269   if (animated) {
1270     // We pass false for aAllowInvalidation because we may be asked to use
1271     // async notifications. Any potential invalidation here will be sent when
1272     // RequestRefresh is called, or NotifyDecodeComplete.
1273 #ifdef DEBUG
1274     IntRect rect =
1275 #endif
1276         mAnimationState->UpdateState(this, ToUnoriented(mSize).ToUnknownSize(),
1277                                      false);
1278     MOZ_ASSERT(rect.IsEmpty());
1279   }
1280 
1281   // Make sure DecoderFactory was able to create a decoder successfully.
1282   if (NS_FAILED(rv)) {
1283     MOZ_ASSERT(!task);
1284     aOutFailed = true;
1285     return;
1286   }
1287 
1288   MOZ_ASSERT(task);
1289   mDecodeCount++;
1290 
1291   // We're ready to decode; start the decoder.
1292   aOutRanSync = LaunchDecodingTask(task, this, aFlags, LoadAllSourceData());
1293 }
1294 
1295 NS_IMETHODIMP
DecodeMetadata(uint32_t aFlags)1296 RasterImage::DecodeMetadata(uint32_t aFlags) {
1297   if (mError) {
1298     return NS_ERROR_FAILURE;
1299   }
1300 
1301   MOZ_ASSERT(!LoadHasSize(), "Should not do unnecessary metadata decodes");
1302 
1303   // Create a decoder.
1304   RefPtr<IDecodingTask> task = DecoderFactory::CreateMetadataDecoder(
1305       mDecoderType, WrapNotNull(this), mSourceBuffer);
1306 
1307   // Make sure DecoderFactory was able to create a decoder successfully.
1308   if (!task) {
1309     return NS_ERROR_FAILURE;
1310   }
1311 
1312   // We're ready to decode; start the decoder.
1313   LaunchDecodingTask(task, this, aFlags, LoadAllSourceData());
1314   return NS_OK;
1315 }
1316 
RecoverFromInvalidFrames(const UnorientedIntSize & aSize,uint32_t aFlags)1317 void RasterImage::RecoverFromInvalidFrames(const UnorientedIntSize& aSize,
1318                                            uint32_t aFlags) {
1319   if (!LoadHasSize()) {
1320     return;
1321   }
1322 
1323   NS_WARNING("A RasterImage's frames became invalid. Attempting to recover...");
1324 
1325   // Discard all existing frames, since they're probably all now invalid.
1326   SurfaceCache::RemoveImage(ImageKey(this));
1327 
1328   // Relock the image if it's supposed to be locked.
1329   if (mLockCount > 0) {
1330     SurfaceCache::LockImage(ImageKey(this));
1331   }
1332 
1333   bool unused1, unused2;
1334 
1335   // Animated images require some special handling, because we normally require
1336   // that they never be discarded.
1337   if (mAnimationState) {
1338     Decode(ToUnoriented(mSize), aFlags | FLAG_SYNC_DECODE,
1339            PlaybackType::eAnimated, unused1, unused2);
1340     ResetAnimation();
1341     return;
1342   }
1343 
1344   // For non-animated images, it's fine to recover using an async decode.
1345   Decode(aSize, aFlags, PlaybackType::eStatic, unused1, unused2);
1346 }
1347 
HaveSkia()1348 static bool HaveSkia() {
1349 #ifdef MOZ_ENABLE_SKIA
1350   return true;
1351 #else
1352   return false;
1353 #endif
1354 }
1355 
CanDownscaleDuringDecode(const UnorientedIntSize & aSize,uint32_t aFlags)1356 bool RasterImage::CanDownscaleDuringDecode(const UnorientedIntSize& aSize,
1357                                            uint32_t aFlags) {
1358   // Check basic requirements: downscale-during-decode is enabled, Skia is
1359   // available, this image isn't transient, we have all the source data and know
1360   // our size, and the flags allow us to do it.
1361   if (!LoadHasSize() || LoadTransient() || !HaveSkia() ||
1362       !StaticPrefs::image_downscale_during_decode_enabled() ||
1363       !(aFlags & imgIContainer::FLAG_HIGH_QUALITY_SCALING)) {
1364     return false;
1365   }
1366 
1367   // We don't downscale animated images during decode.
1368   if (mAnimationState) {
1369     return false;
1370   }
1371 
1372   // Never upscale.
1373   UnorientedIntSize ourSize = ToUnoriented(mSize);
1374   if (aSize.width >= ourSize.width || aSize.height >= ourSize.height) {
1375     return false;
1376   }
1377 
1378   // Zero or negative width or height is unacceptable.
1379   if (aSize.width < 1 || aSize.height < 1) {
1380     return false;
1381   }
1382 
1383   // There's no point in scaling if we can't store the result.
1384   if (!SurfaceCache::CanHold(aSize.ToUnknownSize())) {
1385     return false;
1386   }
1387 
1388   return true;
1389 }
1390 
DrawInternal(DrawableSurface && aSurface,gfxContext * aContext,const UnorientedIntSize & aSize,const ImageRegion & aRegion,SamplingFilter aSamplingFilter,uint32_t aFlags,float aOpacity)1391 ImgDrawResult RasterImage::DrawInternal(DrawableSurface&& aSurface,
1392                                         gfxContext* aContext,
1393                                         const UnorientedIntSize& aSize,
1394                                         const ImageRegion& aRegion,
1395                                         SamplingFilter aSamplingFilter,
1396                                         uint32_t aFlags, float aOpacity) {
1397   gfxContextMatrixAutoSaveRestore saveMatrix(aContext);
1398   ImageRegion region(aRegion);
1399   bool frameIsFinished = aSurface->IsFinished();
1400 
1401   AutoProfilerImagePaintMarker PROFILER_RAII(this);
1402 #ifdef DEBUG
1403   NotifyDrawingObservers();
1404 #endif
1405 
1406   // By now we may have a frame with the requested size. If not, we need to
1407   // adjust the drawing parameters accordingly.
1408   IntSize finalSize = aSurface->GetSize();
1409   bool couldRedecodeForBetterFrame = false;
1410   if (finalSize != aSize.ToUnknownSize()) {
1411     gfx::Size scale(double(aSize.width) / finalSize.width,
1412                     double(aSize.height) / finalSize.height);
1413     aContext->Multiply(gfxMatrix::Scaling(scale.width, scale.height));
1414     region.Scale(1.0 / scale.width, 1.0 / scale.height);
1415 
1416     couldRedecodeForBetterFrame = CanDownscaleDuringDecode(aSize, aFlags);
1417   }
1418 
1419   if (!aSurface->Draw(aContext, region, aSamplingFilter, aFlags, aOpacity)) {
1420     RecoverFromInvalidFrames(aSize, aFlags);
1421     return ImgDrawResult::TEMPORARY_ERROR;
1422   }
1423   if (!frameIsFinished) {
1424     return ImgDrawResult::INCOMPLETE;
1425   }
1426   if (couldRedecodeForBetterFrame) {
1427     return ImgDrawResult::WRONG_SIZE;
1428   }
1429   return ImgDrawResult::SUCCESS;
1430 }
1431 
1432 //******************************************************************************
NS_IMETHODIMP_(ImgDrawResult)1433 NS_IMETHODIMP_(ImgDrawResult)
1434 RasterImage::Draw(gfxContext* aContext, const IntSize& aSize,
1435                   const ImageRegion& aRegion, uint32_t aWhichFrame,
1436                   SamplingFilter aSamplingFilter,
1437                   const Maybe<SVGImageContext>& /*aSVGContext - ignored*/,
1438                   uint32_t aFlags, float aOpacity) {
1439   if (aWhichFrame > FRAME_MAX_VALUE) {
1440     return ImgDrawResult::BAD_ARGS;
1441   }
1442 
1443   if (mError) {
1444     return ImgDrawResult::BAD_IMAGE;
1445   }
1446 
1447   // Illegal -- you can't draw with non-default decode flags.
1448   // (Disabling colorspace conversion might make sense to allow, but
1449   // we don't currently.)
1450   if (ToSurfaceFlags(aFlags) != DefaultSurfaceFlags()) {
1451     return ImgDrawResult::BAD_ARGS;
1452   }
1453 
1454   if (!aContext) {
1455     return ImgDrawResult::BAD_ARGS;
1456   }
1457 
1458   if (mAnimationConsumers == 0) {
1459     SendOnUnlockedDraw(aFlags);
1460   }
1461 
1462   // If we're not using SamplingFilter::GOOD, we shouldn't high-quality scale or
1463   // downscale during decode.
1464   uint32_t flags = aSamplingFilter == SamplingFilter::GOOD
1465                        ? aFlags
1466                        : aFlags & ~FLAG_HIGH_QUALITY_SCALING;
1467 
1468   auto size = ToUnoriented(OrientedIntSize::FromUnknownSize(aSize));
1469   LookupResult result = LookupFrame(size, flags, ToPlaybackType(aWhichFrame),
1470                                     /* aMarkUsed = */ true);
1471   if (!result) {
1472     // Getting the frame (above) touches the image and kicks off decoding.
1473     if (mDrawStartTime.IsNull()) {
1474       mDrawStartTime = TimeStamp::Now();
1475     }
1476     return ImgDrawResult::NOT_READY;
1477   }
1478 
1479   bool shouldRecordTelemetry =
1480       !mDrawStartTime.IsNull() && result.Surface()->IsFinished();
1481 
1482   ImgDrawResult drawResult;
1483   {
1484     gfxContextMatrixAutoSaveRestore asr;
1485     ImageRegion region(aRegion);
1486 
1487     if (!mOrientation.IsIdentity()) {
1488       // Apply a transform so that the unoriented image is drawn in the
1489       // orientation expected by the caller.
1490       gfxMatrix matrix = OrientationMatrix(size);
1491       asr.SetContext(aContext);
1492       aContext->Multiply(matrix);
1493 
1494       // Convert the region to unoriented coordinates.
1495       gfxMatrix inverseMatrix = OrientationMatrix(size, /* aInvert = */ true);
1496       region.TransformBoundsBy(inverseMatrix);
1497     }
1498 
1499     drawResult = DrawInternal(std::move(result.Surface()), aContext, size,
1500                               region, aSamplingFilter, flags, aOpacity);
1501   }
1502 
1503   if (shouldRecordTelemetry) {
1504     TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime;
1505     Telemetry::Accumulate(Telemetry::IMAGE_DECODE_ON_DRAW_LATENCY,
1506                           int32_t(drawLatency.ToMicroseconds()));
1507     mDrawStartTime = TimeStamp();
1508   }
1509 
1510   return drawResult;
1511 }
1512 
1513 //******************************************************************************
1514 
1515 NS_IMETHODIMP
LockImage()1516 RasterImage::LockImage() {
1517   MOZ_ASSERT(NS_IsMainThread(),
1518              "Main thread to encourage serialization with UnlockImage");
1519   if (mError) {
1520     return NS_ERROR_FAILURE;
1521   }
1522 
1523   // Increment the lock count
1524   mLockCount++;
1525 
1526   // Lock this image's surfaces in the SurfaceCache.
1527   if (mLockCount == 1) {
1528     SurfaceCache::LockImage(ImageKey(this));
1529   }
1530 
1531   return NS_OK;
1532 }
1533 
1534 //******************************************************************************
1535 
1536 NS_IMETHODIMP
UnlockImage()1537 RasterImage::UnlockImage() {
1538   MOZ_ASSERT(NS_IsMainThread(),
1539              "Main thread to encourage serialization with LockImage");
1540   if (mError) {
1541     return NS_ERROR_FAILURE;
1542   }
1543 
1544   // It's an error to call this function if the lock count is 0
1545   MOZ_ASSERT(mLockCount > 0, "Calling UnlockImage with mLockCount == 0!");
1546   if (mLockCount == 0) {
1547     return NS_ERROR_ABORT;
1548   }
1549 
1550   // Decrement our lock count
1551   mLockCount--;
1552 
1553   // Unlock this image's surfaces in the SurfaceCache.
1554   if (mLockCount == 0) {
1555     SurfaceCache::UnlockImage(ImageKey(this));
1556   }
1557 
1558   return NS_OK;
1559 }
1560 
1561 //******************************************************************************
1562 
1563 NS_IMETHODIMP
RequestDiscard()1564 RasterImage::RequestDiscard() {
1565   if (LoadDiscardable() &&  // Enabled at creation time...
1566       mLockCount == 0 &&    // ...not temporarily disabled...
1567       CanDiscard()) {
1568     Discard();
1569   }
1570 
1571   return NS_OK;
1572 }
1573 
1574 // Idempotent error flagging routine. If a decoder is open, shuts it down.
DoError()1575 void RasterImage::DoError() {
1576   // If we've flagged an error before, we have nothing to do
1577   if (mError) {
1578     return;
1579   }
1580 
1581   // We can't safely handle errors off-main-thread, so dispatch a worker to
1582   // do it.
1583   if (!NS_IsMainThread()) {
1584     HandleErrorWorker::DispatchIfNeeded(this);
1585     return;
1586   }
1587 
1588   // Put the container in an error state.
1589   mError = true;
1590 
1591   // Stop animation and release our FrameAnimator.
1592   if (mAnimating) {
1593     StopAnimation();
1594   }
1595   mAnimationState = Nothing();
1596   mFrameAnimator = nullptr;
1597 
1598   // Release all locks.
1599   mLockCount = 0;
1600   SurfaceCache::UnlockImage(ImageKey(this));
1601 
1602   // Release all frames from the surface cache.
1603   SurfaceCache::RemoveImage(ImageKey(this));
1604 
1605   // Invalidate to get rid of any partially-drawn image content.
1606   auto dirtyRect = UnorientedIntRect({0, 0}, ToUnoriented(mSize));
1607   NotifyProgress(NoProgress, dirtyRect);
1608 
1609   MOZ_LOG(gImgLog, LogLevel::Error,
1610           ("RasterImage: [this=%p] Error detected for image\n", this));
1611 }
1612 
1613 /* static */
DispatchIfNeeded(RasterImage * aImage)1614 void RasterImage::HandleErrorWorker::DispatchIfNeeded(RasterImage* aImage) {
1615   RefPtr<HandleErrorWorker> worker = new HandleErrorWorker(aImage);
1616   NS_DispatchToMainThread(worker);
1617 }
1618 
HandleErrorWorker(RasterImage * aImage)1619 RasterImage::HandleErrorWorker::HandleErrorWorker(RasterImage* aImage)
1620     : Runnable("image::RasterImage::HandleErrorWorker"), mImage(aImage) {
1621   MOZ_ASSERT(mImage, "Should have image");
1622 }
1623 
1624 NS_IMETHODIMP
Run()1625 RasterImage::HandleErrorWorker::Run() {
1626   mImage->DoError();
1627 
1628   return NS_OK;
1629 }
1630 
ShouldAnimate()1631 bool RasterImage::ShouldAnimate() {
1632   return ImageResource::ShouldAnimate() && mAnimationState &&
1633          mAnimationState->KnownFrameCount() >= 1 && !LoadAnimationFinished();
1634 }
1635 
1636 #ifdef DEBUG
1637 NS_IMETHODIMP
GetFramesNotified(uint32_t * aFramesNotified)1638 RasterImage::GetFramesNotified(uint32_t* aFramesNotified) {
1639   NS_ENSURE_ARG_POINTER(aFramesNotified);
1640 
1641   *aFramesNotified = mFramesNotified;
1642 
1643   return NS_OK;
1644 }
1645 #endif
1646 
NotifyProgress(Progress aProgress,const UnorientedIntRect & aInvalidRect,const Maybe<uint32_t> & aFrameCount,DecoderFlags aDecoderFlags,SurfaceFlags aSurfaceFlags)1647 void RasterImage::NotifyProgress(
1648     Progress aProgress,
1649     const UnorientedIntRect& aInvalidRect /* = UnorientedIntRect() */,
1650     const Maybe<uint32_t>& aFrameCount /* = Nothing() */,
1651     DecoderFlags aDecoderFlags /* = DefaultDecoderFlags() */,
1652     SurfaceFlags aSurfaceFlags /* = DefaultSurfaceFlags() */) {
1653   MOZ_ASSERT(NS_IsMainThread());
1654 
1655   // Ensure that we stay alive long enough to finish notifying.
1656   RefPtr<RasterImage> image = this;
1657 
1658   UnorientedIntRect invalidRect = aInvalidRect;
1659 
1660   if (!(aDecoderFlags & DecoderFlags::FIRST_FRAME_ONLY)) {
1661     // We may have decoded new animation frames; update our animation state.
1662     MOZ_ASSERT_IF(aFrameCount && *aFrameCount > 1, mAnimationState || mError);
1663     if (mAnimationState && aFrameCount) {
1664       mAnimationState->UpdateKnownFrameCount(*aFrameCount);
1665     }
1666 
1667     // If we should start animating right now, do so.
1668     if (mAnimationState && aFrameCount == Some(1u) && LoadPendingAnimation() &&
1669         ShouldAnimate()) {
1670       StartAnimation();
1671     }
1672 
1673     if (mAnimationState) {
1674       auto size = ToUnoriented(mSize);
1675       IntRect rect = mAnimationState->UpdateState(this, size.ToUnknownSize());
1676 
1677       invalidRect.UnionRect(invalidRect,
1678                             UnorientedIntRect::FromUnknownRect(rect));
1679     }
1680   }
1681 
1682   const bool wasDefaultFlags = aSurfaceFlags == DefaultSurfaceFlags();
1683 
1684   auto orientedInvalidRect = ToOriented(invalidRect);
1685 
1686   if (!orientedInvalidRect.IsEmpty() && wasDefaultFlags) {
1687     // Update our image container since we're invalidating.
1688     UpdateImageContainer(Some(orientedInvalidRect.ToUnknownRect()));
1689   }
1690 
1691   // Tell the observers what happened.
1692   image->mProgressTracker->SyncNotifyProgress(
1693       aProgress, orientedInvalidRect.ToUnknownRect());
1694 }
1695 
NotifyDecodeComplete(const DecoderFinalStatus & aStatus,const ImageMetadata & aMetadata,const DecoderTelemetry & aTelemetry,Progress aProgress,const UnorientedIntRect & aInvalidRect,const Maybe<uint32_t> & aFrameCount,DecoderFlags aDecoderFlags,SurfaceFlags aSurfaceFlags)1696 void RasterImage::NotifyDecodeComplete(
1697     const DecoderFinalStatus& aStatus, const ImageMetadata& aMetadata,
1698     const DecoderTelemetry& aTelemetry, Progress aProgress,
1699     const UnorientedIntRect& aInvalidRect, const Maybe<uint32_t>& aFrameCount,
1700     DecoderFlags aDecoderFlags, SurfaceFlags aSurfaceFlags) {
1701   MOZ_ASSERT(NS_IsMainThread());
1702 
1703   // If the decoder detected an error, log it to the error console.
1704   if (aStatus.mShouldReportError) {
1705     ReportDecoderError();
1706   }
1707 
1708   // Record all the metadata the decoder gathered about this image.
1709   bool metadataOK = SetMetadata(aMetadata, aStatus.mWasMetadataDecode);
1710   if (!metadataOK) {
1711     // This indicates a serious error that requires us to discard all existing
1712     // surfaces and redecode to recover. We'll drop the results from this
1713     // decoder on the floor, since they aren't valid.
1714     RecoverFromInvalidFrames(ToUnoriented(mSize),
1715                              FromSurfaceFlags(aSurfaceFlags));
1716     return;
1717   }
1718 
1719   MOZ_ASSERT(mError || LoadHasSize() || !aMetadata.HasSize(),
1720              "SetMetadata should've gotten a size");
1721 
1722   if (!aStatus.mWasMetadataDecode && aStatus.mFinished) {
1723     // Flag that we've been decoded before.
1724     StoreHasBeenDecoded(true);
1725   }
1726 
1727   // Send out any final notifications.
1728   NotifyProgress(aProgress, aInvalidRect, aFrameCount, aDecoderFlags,
1729                  aSurfaceFlags);
1730 
1731   if (!(aDecoderFlags & DecoderFlags::FIRST_FRAME_ONLY)) {
1732     // We may have decoded new animation frames; update our animation state.
1733     MOZ_ASSERT_IF(aFrameCount && *aFrameCount > 1, mAnimationState || mError);
1734     if (mAnimationState && aFrameCount) {
1735       mAnimationState->UpdateKnownFrameCount(*aFrameCount);
1736     }
1737 
1738     // If we should start animating right now, do so.
1739     if (mAnimationState && aFrameCount == Some(1u) && LoadPendingAnimation() &&
1740         ShouldAnimate()) {
1741       StartAnimation();
1742     }
1743 
1744     if (mAnimationState && LoadHasBeenDecoded()) {
1745       // We've finished a full decode of all animation frames and our
1746       // AnimationState has been notified about them all, so let it know not to
1747       // expect anymore.
1748       mAnimationState->NotifyDecodeComplete();
1749 
1750       auto size = ToUnoriented(mSize);
1751       IntRect rect = mAnimationState->UpdateState(this, size.ToUnknownSize());
1752 
1753       if (!rect.IsEmpty()) {
1754         auto dirtyRect = UnorientedIntRect::FromUnknownRect(rect);
1755         NotifyProgress(NoProgress, dirtyRect);
1756       }
1757     }
1758   }
1759 
1760   // Do some telemetry if this isn't a metadata decode.
1761   if (!aStatus.mWasMetadataDecode) {
1762     if (aTelemetry.mChunkCount) {
1763       Telemetry::Accumulate(Telemetry::IMAGE_DECODE_CHUNKS,
1764                             aTelemetry.mChunkCount);
1765     }
1766 
1767     if (aStatus.mFinished) {
1768       Telemetry::Accumulate(Telemetry::IMAGE_DECODE_TIME,
1769                             int32_t(aTelemetry.mDecodeTime.ToMicroseconds()));
1770 
1771       if (aTelemetry.mSpeedHistogram && aTelemetry.mBytesDecoded) {
1772         Telemetry::Accumulate(*aTelemetry.mSpeedHistogram, aTelemetry.Speed());
1773       }
1774     }
1775   }
1776 
1777   // Only act on errors if we have no usable frames from the decoder.
1778   if (aStatus.mHadError &&
1779       (!mAnimationState || mAnimationState->KnownFrameCount() == 0)) {
1780     DoError();
1781   } else if (aStatus.mWasMetadataDecode && !LoadHasSize()) {
1782     DoError();
1783   }
1784 
1785   // XXX(aosmond): Can we get this far without mFinished == true?
1786   if (aStatus.mFinished && aStatus.mWasMetadataDecode) {
1787     // If we were waiting to fire the load event, go ahead and fire it now.
1788     if (mLoadProgress) {
1789       NotifyForLoadEvent(*mLoadProgress);
1790       mLoadProgress = Nothing();
1791     }
1792 
1793     // If we were a metadata decode and a full decode was requested, do it.
1794     if (LoadWantFullDecode()) {
1795       StoreWantFullDecode(false);
1796       RequestDecodeForSize(mSize.ToUnknownSize(),
1797                            DECODE_FLAGS_DEFAULT | FLAG_HIGH_QUALITY_SCALING,
1798                            FRAME_CURRENT);
1799     }
1800   }
1801 }
1802 
ReportDecoderError()1803 void RasterImage::ReportDecoderError() {
1804   nsCOMPtr<nsIConsoleService> consoleService =
1805       do_GetService(NS_CONSOLESERVICE_CONTRACTID);
1806   nsCOMPtr<nsIScriptError> errorObject =
1807       do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
1808 
1809   if (consoleService && errorObject) {
1810     nsAutoString msg(u"Image corrupt or truncated."_ns);
1811     nsAutoString src;
1812     if (GetURI()) {
1813       nsAutoCString uri;
1814       if (!GetSpecTruncatedTo1k(uri)) {
1815         msg += u" URI in this note truncated due to length."_ns;
1816       }
1817       CopyUTF8toUTF16(uri, src);
1818     }
1819     if (NS_SUCCEEDED(errorObject->InitWithWindowID(msg, src, u""_ns, 0, 0,
1820                                                    nsIScriptError::errorFlag,
1821                                                    "Image", InnerWindowID()))) {
1822       consoleService->LogMessage(errorObject);
1823     }
1824   }
1825 }
1826 
Unwrap()1827 already_AddRefed<imgIContainer> RasterImage::Unwrap() {
1828   nsCOMPtr<imgIContainer> self(this);
1829   return self.forget();
1830 }
1831 
PropagateUseCounters(dom::Document *)1832 void RasterImage::PropagateUseCounters(dom::Document*) {
1833   // No use counters.
1834 }
1835 
OptimalImageSizeForDest(const gfxSize & aDest,uint32_t aWhichFrame,SamplingFilter aSamplingFilter,uint32_t aFlags)1836 IntSize RasterImage::OptimalImageSizeForDest(const gfxSize& aDest,
1837                                              uint32_t aWhichFrame,
1838                                              SamplingFilter aSamplingFilter,
1839                                              uint32_t aFlags) {
1840   MOZ_ASSERT(aDest.width >= 0 || ceil(aDest.width) <= INT32_MAX ||
1841                  aDest.height >= 0 || ceil(aDest.height) <= INT32_MAX,
1842              "Unexpected destination size");
1843 
1844   if (mSize.IsEmpty() || aDest.IsEmpty()) {
1845     return IntSize(0, 0);
1846   }
1847 
1848   auto dest = OrientedIntSize::FromUnknownSize(
1849       IntSize::Ceil(aDest.width, aDest.height));
1850 
1851   if (aSamplingFilter == SamplingFilter::GOOD &&
1852       CanDownscaleDuringDecode(ToUnoriented(dest), aFlags)) {
1853     return dest.ToUnknownSize();
1854   }
1855 
1856   // We can't scale to this size. Use our intrinsic size for now.
1857   return mSize.ToUnknownSize();
1858 }
1859 
OrientationMatrix(const UnorientedIntSize & aSize,bool aInvert) const1860 gfxMatrix RasterImage::OrientationMatrix(const UnorientedIntSize& aSize,
1861                                          bool aInvert) const {
1862   return OrientedImage::OrientationMatrix(mOrientation, aSize.ToUnknownSize(),
1863                                           aInvert);
1864 }
1865 
1866 /**
1867  * Rotate aRect by the given angle within the space specified by aSize.
1868  *
1869  * For example, with aRect = [20, 10, 5, 5] and aSize = [100, 100], rotating
1870  * with Angle::D90 will result in aRect = [85, 20, 5, 5].
1871  */
Rotate(IntRect & aRect,const IntSize & aSize,Angle aAngle)1872 static void Rotate(IntRect& aRect, const IntSize& aSize, Angle aAngle) {
1873   switch (aAngle) {
1874     case Angle::D0:
1875       break;
1876     case Angle::D90:
1877       aRect = {aSize.height - aRect.YMost(), aRect.x, aRect.height,
1878                aRect.width};
1879       break;
1880     case Angle::D180:
1881       aRect.MoveTo(aSize.width - aRect.XMost(), aSize.height - aRect.YMost());
1882       break;
1883     case Angle::D270:
1884       aRect = {aRect.y, aSize.width - aRect.XMost(), aRect.height, aRect.width};
1885       break;
1886   }
1887 }
1888 
1889 /**
1890  * Flip aRect along the central axis within aSize.
1891  *
1892  * For example, with aRect = [20, 10, 5, 5] and aSize = [100, 100], flipping
1893  * with Flip::Horizontal will result in aRect = [75, 10, 5, 5].
1894  */
Flip(IntRect & aRect,const IntSize & aSize,Flip aFlip)1895 static void Flip(IntRect& aRect, const IntSize& aSize, Flip aFlip) {
1896   switch (aFlip) {
1897     case Flip::Unflipped:
1898       break;
1899     case Flip::Horizontal:
1900       aRect.x = aSize.width - aRect.XMost();
1901       break;
1902   }
1903 }
1904 
ToOriented(UnorientedIntRect aRect) const1905 OrientedIntRect RasterImage::ToOriented(UnorientedIntRect aRect) const {
1906   IntRect rect = aRect.ToUnknownRect();
1907   auto size = ToUnoriented(mSize);
1908 
1909   MOZ_ASSERT(!mOrientation.flipFirst,
1910              "flipFirst should only be used by OrientedImage");
1911 
1912   // mOrientation specifies the transformation from a correctly oriented image
1913   // to the pixels stored in the file, so we need to rotate by the negation of
1914   // the given angle.
1915   Angle angle = Orientation::InvertAngle(mOrientation.rotation);
1916   Rotate(rect, size.ToUnknownSize(), angle);
1917 
1918   // Use mSize instead of size, since after the Rotate call, the size of the
1919   // space that rect is in has had its width and height swapped.
1920   Flip(rect, mSize.ToUnknownSize(), mOrientation.flip);
1921 
1922   return OrientedIntRect::FromUnknownRect(rect);
1923 }
1924 
ToUnoriented(OrientedIntRect aRect) const1925 UnorientedIntRect RasterImage::ToUnoriented(OrientedIntRect aRect) const {
1926   IntRect rect = aRect.ToUnknownRect();
1927 
1928   Flip(rect, mSize.ToUnknownSize(), mOrientation.flip);
1929   Rotate(rect, mSize.ToUnknownSize(), mOrientation.rotation);
1930 
1931   MOZ_ASSERT(!mOrientation.flipFirst,
1932              "flipFirst should only be used by OrientedImage");
1933 
1934   return UnorientedIntRect::FromUnknownRect(rect);
1935 }
1936 
1937 }  // namespace image
1938 }  // namespace mozilla
1939