Coverage Report

Created: 2018-09-25 14:53

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