Source code

Revision control

Other Tools

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