image/src/RasterImage.cpp

branch
TOR_BUG_9701
changeset 10
ac0c01689b40
equal deleted inserted replaced
-1:000000000000 0:eaf53dde8935
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 that #include prlog.h
7 #include "ImageLogging.h"
8
9 #include "RasterImage.h"
10
11 #include "base/histogram.h"
12 #include "gfxPlatform.h"
13 #include "nsComponentManagerUtils.h"
14 #include "imgDecoderObserver.h"
15 #include "nsError.h"
16 #include "Decoder.h"
17 #include "nsAutoPtr.h"
18 #include "prenv.h"
19 #include "prsystem.h"
20 #include "ImageContainer.h"
21 #include "Layers.h"
22 #include "nsPresContext.h"
23 #include "nsIThreadPool.h"
24 #include "nsXPCOMCIDInternal.h"
25 #include "nsIObserverService.h"
26 #include "FrameAnimator.h"
27
28 #include "nsPNGDecoder.h"
29 #include "nsGIFDecoder2.h"
30 #include "nsJPEGDecoder.h"
31 #include "nsBMPDecoder.h"
32 #include "nsICODecoder.h"
33 #include "nsIconDecoder.h"
34
35 #include "gfxContext.h"
36
37 #include "mozilla/gfx/2D.h"
38 #include "mozilla/RefPtr.h"
39 #include "mozilla/MemoryReporting.h"
40 #include "mozilla/Services.h"
41 #include "mozilla/Preferences.h"
42 #include <stdint.h>
43 #include "mozilla/Telemetry.h"
44 #include "mozilla/TimeStamp.h"
45 #include "mozilla/ClearOnShutdown.h"
46 #include "mozilla/gfx/Scale.h"
47
48 #include "GeckoProfiler.h"
49 #include "gfx2DGlue.h"
50 #include <algorithm>
51
52 #ifdef MOZ_NUWA_PROCESS
53 #include "ipc/Nuwa.h"
54 #endif
55
56 using namespace mozilla;
57 using namespace mozilla::gfx;
58 using namespace mozilla::image;
59 using namespace mozilla::layers;
60
61 // a mask for flags that will affect the decoding
62 #define DECODE_FLAGS_MASK (imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA | imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION)
63 #define DECODE_FLAGS_DEFAULT 0
64
65 /* Accounting for compressed data */
66 #if defined(PR_LOGGING)
67 static PRLogModuleInfo *
68 GetCompressedImageAccountingLog()
69 {
70 static PRLogModuleInfo *sLog;
71 if (!sLog)
72 sLog = PR_NewLogModule("CompressedImageAccounting");
73 return sLog;
74 }
75 #else
76 #define GetCompressedImageAccountingLog()
77 #endif
78
79 // Tweakable progressive decoding parameters. These are initialized to 0 here
80 // because otherwise, we have to initialize them in a static initializer, which
81 // makes us slower to start up.
82 static uint32_t gDecodeBytesAtATime = 0;
83 static uint32_t gMaxMSBeforeYield = 0;
84 static bool gHQDownscaling = false;
85 // This is interpreted as a floating-point value / 1000
86 static uint32_t gHQDownscalingMinFactor = 1000;
87 static bool gMultithreadedDecoding = true;
88 static int32_t gDecodingThreadLimit = -1;
89 // The number of pixels in a 5 megapixel decoded image.
90 // Equivalent to an example 3125x1600 resolution.
91 static uint32_t gHQUpscalingMaxSize = 20971520;
92
93 // The maximum number of times any one RasterImage was decoded. This is only
94 // used for statistics.
95 static int32_t sMaxDecodeCount = 0;
96
97 static void
98 InitPrefCaches()
99 {
100 Preferences::AddUintVarCache(&gDecodeBytesAtATime,
101 "image.mem.decode_bytes_at_a_time", 200000);
102 Preferences::AddUintVarCache(&gMaxMSBeforeYield,
103 "image.mem.max_ms_before_yield", 400);
104 Preferences::AddBoolVarCache(&gHQDownscaling,
105 "image.high_quality_downscaling.enabled", false);
106 Preferences::AddUintVarCache(&gHQDownscalingMinFactor,
107 "image.high_quality_downscaling.min_factor", 1000);
108 Preferences::AddBoolVarCache(&gMultithreadedDecoding,
109 "image.multithreaded_decoding.enabled", true);
110 Preferences::AddIntVarCache(&gDecodingThreadLimit,
111 "image.multithreaded_decoding.limit", -1);
112 Preferences::AddUintVarCache(&gHQUpscalingMaxSize,
113 "image.high_quality_upscaling.max_size", 20971520);
114 }
115
116 /* We define our own error checking macros here for 2 reasons:
117 *
118 * 1) Most of the failures we encounter here will (hopefully) be
119 * the result of decoding failures (ie, bad data) and not code
120 * failures. As such, we don't want to clutter up debug consoles
121 * with spurious messages about NS_ENSURE_SUCCESS failures.
122 *
123 * 2) We want to set the internal error flag, shutdown properly,
124 * and end up in an error state.
125 *
126 * So this macro should be called when the desired failure behavior
127 * is to put the container into an error state and return failure.
128 * It goes without saying that macro won't compile outside of a
129 * non-static RasterImage method.
130 */
131 #define LOG_CONTAINER_ERROR \
132 PR_BEGIN_MACRO \
133 PR_LOG (GetImgLog(), PR_LOG_ERROR, \
134 ("RasterImage: [this=%p] Error " \
135 "detected at line %u for image of " \
136 "type %s\n", this, __LINE__, \
137 mSourceDataMimeType.get())); \
138 PR_END_MACRO
139
140 #define CONTAINER_ENSURE_SUCCESS(status) \
141 PR_BEGIN_MACRO \
142 nsresult _status = status; /* eval once */ \
143 if (NS_FAILED(_status)) { \
144 LOG_CONTAINER_ERROR; \
145 DoError(); \
146 return _status; \
147 } \
148 PR_END_MACRO
149
150 #define CONTAINER_ENSURE_TRUE(arg, rv) \
151 PR_BEGIN_MACRO \
152 if (!(arg)) { \
153 LOG_CONTAINER_ERROR; \
154 DoError(); \
155 return rv; \
156 } \
157 PR_END_MACRO
158
159
160
161 static int num_containers;
162 static int num_discardable_containers;
163 static int64_t total_source_bytes;
164 static int64_t discardable_source_bytes;
165
166 /* Are we globally disabling image discarding? */
167 static bool
168 DiscardingEnabled()
169 {
170 static bool inited;
171 static bool enabled;
172
173 if (!inited) {
174 inited = true;
175
176 enabled = (PR_GetEnv("MOZ_DISABLE_IMAGE_DISCARD") == nullptr);
177 }
178
179 return enabled;
180 }
181
182 class ScaleRequest
183 {
184 public:
185 ScaleRequest(RasterImage* aImage, const gfxSize& aScale, imgFrame* aSrcFrame)
186 : scale(aScale)
187 , dstLocked(false)
188 , done(false)
189 , stopped(false)
190 {
191 MOZ_ASSERT(!aSrcFrame->GetIsPaletted());
192 MOZ_ASSERT(aScale.width > 0 && aScale.height > 0);
193
194 weakImage = aImage->asWeakPtr();
195 srcRect = aSrcFrame->GetRect();
196
197 nsIntRect dstRect = srcRect;
198 dstRect.ScaleRoundOut(scale.width, scale.height);
199 dstSize = dstRect.Size();
200 }
201
202 // This can only be called on the main thread.
203 bool GetSurfaces(imgFrame* srcFrame)
204 {
205 MOZ_ASSERT(NS_IsMainThread());
206
207 nsRefPtr<RasterImage> image = weakImage.get();
208 if (!image) {
209 return false;
210 }
211
212 bool success = false;
213 if (!dstLocked) {
214 // We need to hold a lock onto the RasterImage object itself so that
215 // it (and its associated imgFrames) aren't marked as discardable.
216 bool imgLocked = NS_SUCCEEDED(image->LockImage());
217 bool srcLocked = NS_SUCCEEDED(srcFrame->LockImageData());
218 dstLocked = NS_SUCCEEDED(dstFrame->LockImageData());
219
220 nsRefPtr<gfxASurface> dstASurf;
221 nsRefPtr<gfxASurface> srcASurf;
222 success = srcLocked && NS_SUCCEEDED(srcFrame->GetSurface(getter_AddRefs(srcASurf)));
223 success = success && dstLocked && NS_SUCCEEDED(dstFrame->GetSurface(getter_AddRefs(dstASurf)));
224
225 success = success && imgLocked && srcLocked && dstLocked && srcASurf && dstASurf;
226
227 if (success) {
228 srcSurface = srcASurf->GetAsImageSurface();
229 dstSurface = dstASurf->GetAsImageSurface();
230 srcData = srcSurface->Data();
231 dstData = dstSurface->Data();
232 srcStride = srcSurface->Stride();
233 dstStride = dstSurface->Stride();
234 srcFormat = mozilla::gfx::ImageFormatToSurfaceFormat(srcFrame->GetFormat());
235 }
236
237 // We have references to the Thebes surfaces, so we don't need to leave
238 // the source frame (that we don't own) locked. We'll unlock the
239 // destination frame in ReleaseSurfaces(), below.
240 if (srcLocked) {
241 success = NS_SUCCEEDED(srcFrame->UnlockImageData()) && success;
242 }
243
244 success = success && srcSurface && dstSurface;
245 }
246
247 return success;
248 }
249
250 // This can only be called on the main thread.
251 bool ReleaseSurfaces()
252 {
253 MOZ_ASSERT(NS_IsMainThread());
254
255 nsRefPtr<RasterImage> image = weakImage.get();
256 if (!image) {
257 return false;
258 }
259
260 bool success = false;
261 if (dstLocked) {
262 if (DiscardingEnabled())
263 dstFrame->SetDiscardable();
264 success = NS_SUCCEEDED(dstFrame->UnlockImageData());
265 success = success && NS_SUCCEEDED(image->UnlockImage());
266
267 dstLocked = false;
268 srcData = nullptr;
269 dstData = nullptr;
270 srcSurface = nullptr;
271 dstSurface = nullptr;
272 }
273 return success;
274 }
275
276 // These values may only be touched on the main thread.
277 WeakPtr<RasterImage> weakImage;
278 nsAutoPtr<imgFrame> dstFrame;
279 nsRefPtr<gfxImageSurface> srcSurface;
280 nsRefPtr<gfxImageSurface> dstSurface;
281
282 // Below are the values that may be touched on the scaling thread.
283 gfxSize scale;
284 uint8_t* srcData;
285 uint8_t* dstData;
286 nsIntRect srcRect;
287 gfxIntSize dstSize;
288 uint32_t srcStride;
289 uint32_t dstStride;
290 mozilla::gfx::SurfaceFormat srcFormat;
291 bool dstLocked;
292 bool done;
293 // This boolean is accessed from both threads simultaneously without locking.
294 // That's safe because stopping a ScaleRequest is strictly an optimization;
295 // if we're not cache-coherent, at worst we'll do extra work.
296 bool stopped;
297 };
298
299 class DrawRunner : public nsRunnable
300 {
301 public:
302 DrawRunner(ScaleRequest* request)
303 : mScaleRequest(request)
304 {}
305
306 NS_IMETHOD Run()
307 {
308 // ScaleWorker is finished with this request, so we can unlock the data now.
309 mScaleRequest->ReleaseSurfaces();
310
311 nsRefPtr<RasterImage> image = mScaleRequest->weakImage.get();
312
313 if (image) {
314 RasterImage::ScaleStatus status;
315 if (mScaleRequest->done) {
316 status = RasterImage::SCALE_DONE;
317 } else {
318 status = RasterImage::SCALE_INVALID;
319 }
320
321 image->ScalingDone(mScaleRequest, status);
322 }
323
324 return NS_OK;
325 }
326
327 private: /* members */
328 nsAutoPtr<ScaleRequest> mScaleRequest;
329 };
330
331 class ScaleRunner : public nsRunnable
332 {
333 public:
334 ScaleRunner(RasterImage* aImage, const gfxSize& aScale, imgFrame* aSrcFrame)
335 {
336 nsAutoPtr<ScaleRequest> request(new ScaleRequest(aImage, aScale, aSrcFrame));
337
338 // Destination is unconditionally ARGB32 because that's what the scaler
339 // outputs.
340 request->dstFrame = new imgFrame();
341 nsresult rv = request->dstFrame->Init(0, 0, request->dstSize.width, request->dstSize.height,
342 gfxImageFormat::ARGB32);
343
344 if (NS_FAILED(rv) || !request->GetSurfaces(aSrcFrame)) {
345 return;
346 }
347
348 aImage->ScalingStart(request);
349
350 mScaleRequest = request;
351 }
352
353 NS_IMETHOD Run()
354 {
355 // An alias just for ease of typing
356 ScaleRequest* request = mScaleRequest;
357
358 if (!request->stopped) {
359 request->done = mozilla::gfx::Scale(request->srcData, request->srcRect.width, request->srcRect.height, request->srcStride,
360 request->dstData, request->dstSize.width, request->dstSize.height, request->dstStride,
361 request->srcFormat);
362 } else {
363 request->done = false;
364 }
365
366 // OK, we've got a new scaled image. Let's get the main thread to unlock and
367 // redraw it.
368 nsRefPtr<DrawRunner> runner = new DrawRunner(mScaleRequest.forget());
369 NS_DispatchToMainThread(runner, NS_DISPATCH_NORMAL);
370
371 return NS_OK;
372 }
373
374 bool IsOK() const { return !!mScaleRequest; }
375
376 private:
377 nsAutoPtr<ScaleRequest> mScaleRequest;
378 };
379
380 namespace mozilla {
381 namespace image {
382
383 /* static */ StaticRefPtr<RasterImage::DecodePool> RasterImage::DecodePool::sSingleton;
384 static nsCOMPtr<nsIThread> sScaleWorkerThread = nullptr;
385
386 #ifndef DEBUG
387 NS_IMPL_ISUPPORTS(RasterImage, imgIContainer, nsIProperties)
388 #else
389 NS_IMPL_ISUPPORTS(RasterImage, imgIContainer, nsIProperties,
390 imgIContainerDebug)
391 #endif
392
393 //******************************************************************************
394 RasterImage::RasterImage(imgStatusTracker* aStatusTracker,
395 ImageURL* aURI /* = nullptr */) :
396 ImageResource(aURI), // invoke superclass's constructor
397 mSize(0,0),
398 mFrameDecodeFlags(DECODE_FLAGS_DEFAULT),
399 mMultipartDecodedFrame(nullptr),
400 mAnim(nullptr),
401 mLockCount(0),
402 mDecodeCount(0),
403 mRequestedSampleSize(0),
404 #ifdef DEBUG
405 mFramesNotified(0),
406 #endif
407 mDecodingMonitor("RasterImage Decoding Monitor"),
408 mDecoder(nullptr),
409 mBytesDecoded(0),
410 mInDecoder(false),
411 mStatusDiff(ImageStatusDiff::NoChange()),
412 mNotifying(false),
413 mHasSize(false),
414 mDecodeOnDraw(false),
415 mMultipart(false),
416 mDiscardable(false),
417 mHasSourceData(false),
418 mDecoded(false),
419 mHasBeenDecoded(false),
420 mAnimationFinished(false),
421 mFinishing(false),
422 mInUpdateImageContainer(false),
423 mWantFullDecode(false),
424 mPendingError(false),
425 mScaleRequest(nullptr)
426 {
427 mStatusTrackerInit = new imgStatusTrackerInit(this, aStatusTracker);
428
429 // Set up the discard tracker node.
430 mDiscardTrackerNode.img = this;
431 Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(0);
432
433 // Statistics
434 num_containers++;
435 }
436
437 //******************************************************************************
438 RasterImage::~RasterImage()
439 {
440 // Discardable statistics
441 if (mDiscardable) {
442 num_discardable_containers--;
443 discardable_source_bytes -= mSourceData.Length();
444
445 PR_LOG (GetCompressedImageAccountingLog(), PR_LOG_DEBUG,
446 ("CompressedImageAccounting: destroying RasterImage %p. "
447 "Total Containers: %d, Discardable containers: %d, "
448 "Total source bytes: %lld, Source bytes for discardable containers %lld",
449 this,
450 num_containers,
451 num_discardable_containers,
452 total_source_bytes,
453 discardable_source_bytes));
454 }
455
456 if (mDecoder) {
457 // Kill off our decode request, if it's pending. (If not, this call is
458 // harmless.)
459 ReentrantMonitorAutoEnter lock(mDecodingMonitor);
460 DecodePool::StopDecoding(this);
461 mDecoder = nullptr;
462
463 // Unlock the last frame (if we have any). Our invariant is that, while we
464 // have a decoder open, the last frame is always locked.
465 // This would be done in ShutdownDecoder, but since mDecoder is non-null,
466 // we didn't call ShutdownDecoder and we need to do it manually.
467 if (GetNumFrames() > 0) {
468 imgFrame *curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1);
469 curframe->UnlockImageData();
470 }
471 }
472
473 delete mAnim;
474 mAnim = nullptr;
475 delete mMultipartDecodedFrame;
476
477 // Total statistics
478 num_containers--;
479 total_source_bytes -= mSourceData.Length();
480
481 if (NS_IsMainThread()) {
482 DiscardTracker::Remove(&mDiscardTrackerNode);
483 }
484 }
485
486 /* static */ void
487 RasterImage::Initialize()
488 {
489 InitPrefCaches();
490
491 // Create our singletons now, so we don't have to worry about what thread
492 // they're created on.
493 DecodePool::Singleton();
494 }
495
496 nsresult
497 RasterImage::Init(const char* aMimeType,
498 uint32_t aFlags)
499 {
500 // We don't support re-initialization
501 if (mInitialized)
502 return NS_ERROR_ILLEGAL_VALUE;
503
504 // Not sure an error can happen before init, but be safe
505 if (mError)
506 return NS_ERROR_FAILURE;
507
508 NS_ENSURE_ARG_POINTER(aMimeType);
509
510 // We must be non-discardable and non-decode-on-draw for
511 // multipart channels
512 NS_ABORT_IF_FALSE(!(aFlags & INIT_FLAG_MULTIPART) ||
513 (!(aFlags & INIT_FLAG_DISCARDABLE) &&
514 !(aFlags & INIT_FLAG_DECODE_ON_DRAW)),
515 "Can't be discardable or decode-on-draw for multipart");
516
517 // Store initialization data
518 mSourceDataMimeType.Assign(aMimeType);
519 mDiscardable = !!(aFlags & INIT_FLAG_DISCARDABLE);
520 mDecodeOnDraw = !!(aFlags & INIT_FLAG_DECODE_ON_DRAW);
521 mMultipart = !!(aFlags & INIT_FLAG_MULTIPART);
522
523 // Statistics
524 if (mDiscardable) {
525 num_discardable_containers++;
526 discardable_source_bytes += mSourceData.Length();
527 }
528
529 // Instantiate the decoder
530 nsresult rv = InitDecoder(/* aDoSizeDecode = */ true);
531 CONTAINER_ENSURE_SUCCESS(rv);
532
533 // If we aren't storing source data, we want to switch from a size decode to
534 // a full decode as soon as possible.
535 if (!StoringSourceData()) {
536 mWantFullDecode = true;
537 }
538
539 // Mark us as initialized
540 mInitialized = true;
541
542 return NS_OK;
543 }
544
545 //******************************************************************************
546 // [notxpcom] void requestRefresh ([const] in TimeStamp aTime);
547 NS_IMETHODIMP_(void)
548 RasterImage::RequestRefresh(const mozilla::TimeStamp& aTime)
549 {
550 EvaluateAnimation();
551
552 if (!mAnimating) {
553 return;
554 }
555
556 FrameAnimator::RefreshResult res;
557 if (mAnim) {
558 res = mAnim->RequestRefresh(aTime);
559 }
560
561 if (res.frameAdvanced) {
562 // Notify listeners that our frame has actually changed, but do this only
563 // once for all frames that we've now passed (if AdvanceFrame() was called
564 // more than once).
565 #ifdef DEBUG
566 mFramesNotified++;
567 #endif
568
569 UpdateImageContainer();
570
571 // Explicitly call this on mStatusTracker so we're sure to not interfere
572 // with the decoding process
573 if (mStatusTracker)
574 mStatusTracker->FrameChanged(&res.dirtyRect);
575 }
576
577 if (res.animationFinished) {
578 mAnimationFinished = true;
579 EvaluateAnimation();
580 }
581 }
582
583 //******************************************************************************
584 /* readonly attribute int32_t width; */
585 NS_IMETHODIMP
586 RasterImage::GetWidth(int32_t *aWidth)
587 {
588 NS_ENSURE_ARG_POINTER(aWidth);
589
590 if (mError) {
591 *aWidth = 0;
592 return NS_ERROR_FAILURE;
593 }
594
595 *aWidth = mSize.width;
596 return NS_OK;
597 }
598
599 //******************************************************************************
600 /* readonly attribute int32_t height; */
601 NS_IMETHODIMP
602 RasterImage::GetHeight(int32_t *aHeight)
603 {
604 NS_ENSURE_ARG_POINTER(aHeight);
605
606 if (mError) {
607 *aHeight = 0;
608 return NS_ERROR_FAILURE;
609 }
610
611 *aHeight = mSize.height;
612 return NS_OK;
613 }
614
615 //******************************************************************************
616 /* [noscript] readonly attribute nsSize intrinsicSize; */
617 NS_IMETHODIMP
618 RasterImage::GetIntrinsicSize(nsSize* aSize)
619 {
620 if (mError)
621 return NS_ERROR_FAILURE;
622
623 *aSize = nsSize(nsPresContext::CSSPixelsToAppUnits(mSize.width),
624 nsPresContext::CSSPixelsToAppUnits(mSize.height));
625 return NS_OK;
626 }
627
628 //******************************************************************************
629 /* [noscript] readonly attribute nsSize intrinsicRatio; */
630 NS_IMETHODIMP
631 RasterImage::GetIntrinsicRatio(nsSize* aRatio)
632 {
633 if (mError)
634 return NS_ERROR_FAILURE;
635
636 *aRatio = nsSize(mSize.width, mSize.height);
637 return NS_OK;
638 }
639
640 NS_IMETHODIMP_(Orientation)
641 RasterImage::GetOrientation()
642 {
643 return mOrientation;
644 }
645
646 //******************************************************************************
647 /* unsigned short GetType(); */
648 NS_IMETHODIMP
649 RasterImage::GetType(uint16_t *aType)
650 {
651 NS_ENSURE_ARG_POINTER(aType);
652
653 *aType = GetType();
654 return NS_OK;
655 }
656
657 //******************************************************************************
658 /* [noscript, notxpcom] uint16_t GetType(); */
659 NS_IMETHODIMP_(uint16_t)
660 RasterImage::GetType()
661 {
662 return imgIContainer::TYPE_RASTER;
663 }
664
665 imgFrame*
666 RasterImage::GetImgFrameNoDecode(uint32_t framenum)
667 {
668 if (!mAnim) {
669 NS_ASSERTION(framenum == 0, "Don't ask for a frame > 0 if we're not animated!");
670 return mFrameBlender.GetFrame(0);
671 }
672 return mFrameBlender.GetFrame(framenum);
673 }
674
675 imgFrame*
676 RasterImage::GetImgFrame(uint32_t framenum)
677 {
678 nsresult rv = WantDecodedFrames();
679 CONTAINER_ENSURE_TRUE(NS_SUCCEEDED(rv), nullptr);
680 return GetImgFrameNoDecode(framenum);
681 }
682
683 imgFrame*
684 RasterImage::GetDrawableImgFrame(uint32_t framenum)
685 {
686 imgFrame* frame = nullptr;
687
688 if (mMultipart && framenum == GetCurrentImgFrameIndex()) {
689 // In the multipart case we prefer to use mMultipartDecodedFrame, which is
690 // the most recent one we completely decoded, rather than display the real
691 // current frame and risk severe tearing.
692 frame = mMultipartDecodedFrame;
693 }
694
695 if (!frame) {
696 frame = GetImgFrame(framenum);
697 }
698
699 // We will return a paletted frame if it's not marked as compositing failed
700 // so we can catch crashes for reasons we haven't investigated.
701 if (frame && frame->GetCompositingFailed())
702 return nullptr;
703
704 if (frame) {
705 frame->ApplyDirtToSurfaces();
706 }
707
708 return frame;
709 }
710
711 uint32_t
712 RasterImage::GetCurrentImgFrameIndex() const
713 {
714 if (mAnim)
715 return mAnim->GetCurrentAnimationFrameIndex();
716
717 return 0;
718 }
719
720 imgFrame*
721 RasterImage::GetCurrentImgFrame()
722 {
723 return GetImgFrame(GetCurrentImgFrameIndex());
724 }
725
726 //******************************************************************************
727 /* [notxpcom] boolean frameIsOpaque(in uint32_t aWhichFrame); */
728 NS_IMETHODIMP_(bool)
729 RasterImage::FrameIsOpaque(uint32_t aWhichFrame)
730 {
731 if (aWhichFrame > FRAME_MAX_VALUE) {
732 NS_WARNING("aWhichFrame outside valid range!");
733 return false;
734 }
735
736 if (mError)
737 return false;
738
739 // See if we can get an image frame.
740 imgFrame* frame = aWhichFrame == FRAME_FIRST ? GetImgFrameNoDecode(0)
741 : GetImgFrameNoDecode(GetCurrentImgFrameIndex());
742
743 // If we don't get a frame, the safe answer is "not opaque".
744 if (!frame)
745 return false;
746
747 // Other, the frame is transparent if either:
748 // 1. It needs a background.
749 // 2. Its size doesn't cover our entire area.
750 nsIntRect framerect = frame->GetRect();
751 return !frame->GetNeedsBackground() &&
752 framerect.IsEqualInterior(nsIntRect(0, 0, mSize.width, mSize.height));
753 }
754
755 nsIntRect
756 RasterImage::FrameRect(uint32_t aWhichFrame)
757 {
758 if (aWhichFrame > FRAME_MAX_VALUE) {
759 NS_WARNING("aWhichFrame outside valid range!");
760 return nsIntRect();
761 }
762
763 // Get the requested frame.
764 imgFrame* frame = aWhichFrame == FRAME_FIRST ? GetImgFrameNoDecode(0)
765 : GetImgFrameNoDecode(GetCurrentImgFrameIndex());
766
767 // If we have the frame, use that rectangle.
768 if (frame) {
769 return frame->GetRect();
770 }
771
772 // If the frame doesn't exist, we return the empty rectangle. It's not clear
773 // whether this is appropriate in general, but at the moment the only
774 // consumer of this method is imgStatusTracker (when it wants to figure out
775 // dirty rectangles to send out batched observer updates). This should
776 // probably be revisited when we fix bug 503973.
777 return nsIntRect();
778 }
779
780 uint32_t
781 RasterImage::GetCurrentFrameIndex()
782 {
783 return GetCurrentImgFrameIndex();
784 }
785
786 uint32_t
787 RasterImage::GetNumFrames() const
788 {
789 return mFrameBlender.GetNumFrames();
790 }
791
792 //******************************************************************************
793 /* readonly attribute boolean animated; */
794 NS_IMETHODIMP
795 RasterImage::GetAnimated(bool *aAnimated)
796 {
797 if (mError)
798 return NS_ERROR_FAILURE;
799
800 NS_ENSURE_ARG_POINTER(aAnimated);
801
802 // If we have mAnim, we can know for sure
803 if (mAnim) {
804 *aAnimated = true;
805 return NS_OK;
806 }
807
808 // Otherwise, we need to have been decoded to know for sure, since if we were
809 // decoded at least once mAnim would have been created for animated images
810 if (!mHasBeenDecoded)
811 return NS_ERROR_NOT_AVAILABLE;
812
813 // We know for sure
814 *aAnimated = false;
815
816 return NS_OK;
817 }
818
819 //******************************************************************************
820 /* [notxpcom] int32_t getFirstFrameDelay (); */
821 NS_IMETHODIMP_(int32_t)
822 RasterImage::GetFirstFrameDelay()
823 {
824 if (mError)
825 return -1;
826
827 bool animated = false;
828 if (NS_FAILED(GetAnimated(&animated)) || !animated)
829 return -1;
830
831 return mFrameBlender.GetTimeoutForFrame(0);
832 }
833
834 nsresult
835 RasterImage::CopyFrame(uint32_t aWhichFrame,
836 uint32_t aFlags,
837 gfxImageSurface **_retval)
838 {
839 if (aWhichFrame > FRAME_MAX_VALUE)
840 return NS_ERROR_INVALID_ARG;
841
842 if (mError)
843 return NS_ERROR_FAILURE;
844
845 // Disallowed in the API
846 if (mInDecoder && (aFlags & imgIContainer::FLAG_SYNC_DECODE))
847 return NS_ERROR_FAILURE;
848
849 nsresult rv;
850
851 if (!ApplyDecodeFlags(aFlags, aWhichFrame))
852 return NS_ERROR_NOT_AVAILABLE;
853
854 // If requested, synchronously flush any data we have lying around to the decoder
855 if (aFlags & FLAG_SYNC_DECODE) {
856 rv = SyncDecode();
857 CONTAINER_ENSURE_SUCCESS(rv);
858 }
859
860 NS_ENSURE_ARG_POINTER(_retval);
861
862 // Get the frame. If it's not there, it's probably the caller's fault for
863 // not waiting for the data to be loaded from the network or not passing
864 // FLAG_SYNC_DECODE
865 uint32_t frameIndex = (aWhichFrame == FRAME_FIRST) ?
866 0 : GetCurrentImgFrameIndex();
867 imgFrame *frame = GetDrawableImgFrame(frameIndex);
868 if (!frame) {
869 *_retval = nullptr;
870 return NS_ERROR_FAILURE;
871 }
872
873 nsRefPtr<gfxPattern> pattern;
874 frame->GetPattern(getter_AddRefs(pattern));
875 nsIntRect intframerect = frame->GetRect();
876 gfxRect framerect(intframerect.x, intframerect.y, intframerect.width, intframerect.height);
877
878 // Create a 32-bit image surface of our size, but draw using the frame's
879 // rect, implicitly padding the frame out to the image's size.
880 nsRefPtr<gfxImageSurface> imgsurface = new gfxImageSurface(gfxIntSize(mSize.width, mSize.height),
881 gfxImageFormat::ARGB32);
882 gfxContext ctx(imgsurface);
883 ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
884 ctx.Rectangle(framerect);
885 ctx.Translate(framerect.TopLeft());
886 ctx.SetPattern(pattern);
887 ctx.Fill();
888
889 imgsurface.forget(_retval);
890 return NS_OK;
891 }
892
893 //******************************************************************************
894 /* [noscript] SourceSurface getFrame(in uint32_t aWhichFrame,
895 * in uint32_t aFlags); */
896 NS_IMETHODIMP_(TemporaryRef<SourceSurface>)
897 RasterImage::GetFrame(uint32_t aWhichFrame,
898 uint32_t aFlags)
899 {
900 MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
901
902 if (aWhichFrame > FRAME_MAX_VALUE)
903 return nullptr;
904
905 if (mError)
906 return nullptr;
907
908 // Disallowed in the API
909 if (mInDecoder && (aFlags & imgIContainer::FLAG_SYNC_DECODE))
910 return nullptr;
911
912 if (!ApplyDecodeFlags(aFlags, aWhichFrame))
913 return nullptr;
914
915 // If the caller requested a synchronous decode, do it
916 if (aFlags & FLAG_SYNC_DECODE) {
917 nsresult rv = SyncDecode();
918 CONTAINER_ENSURE_TRUE(NS_SUCCEEDED(rv), nullptr);
919 }
920
921 // Get the frame. If it's not there, it's probably the caller's fault for
922 // not waiting for the data to be loaded from the network or not passing
923 // FLAG_SYNC_DECODE
924 uint32_t frameIndex = (aWhichFrame == FRAME_FIRST) ?
925 0 : GetCurrentImgFrameIndex();
926 imgFrame *frame = GetDrawableImgFrame(frameIndex);
927 if (!frame) {
928 return nullptr;
929 }
930
931 nsRefPtr<gfxASurface> framesurf;
932
933 // If this frame covers the entire image, we can just reuse its existing
934 // surface.
935 nsIntRect framerect = frame->GetRect();
936 if (framerect.x == 0 && framerect.y == 0 &&
937 framerect.width == mSize.width &&
938 framerect.height == mSize.height) {
939 frame->GetSurface(getter_AddRefs(framesurf));
940 if (!framesurf && !frame->IsSinglePixel()) {
941 // No reason to be optimized away here - the OS threw out the data
942 if (!(aFlags & FLAG_SYNC_DECODE))
943 return nullptr;
944
945 // Unconditionally call ForceDiscard() here because GetSurface can only
946 // return null when we can forcibly discard and redecode. There are two
947 // other cases where GetSurface() can return null - when it is a single
948 // pixel image, which we check before getting here, or when this is an
949 // indexed image, in which case we shouldn't be in this function at all.
950 // The only remaining possibility is that SetDiscardable() was called on
951 // this imgFrame, which implies the image can be redecoded.
952 ForceDiscard();
953 return GetFrame(aWhichFrame, aFlags);
954 }
955 }
956
957 // The image doesn't have a surface because it's been optimized away. Create
958 // one.
959 if (!framesurf) {
960 nsRefPtr<gfxImageSurface> imgsurf;
961 CopyFrame(aWhichFrame, aFlags, getter_AddRefs(imgsurf));
962 framesurf = imgsurf;
963 }
964
965 RefPtr<SourceSurface> result;
966
967 // As far as Moz2D is concerned, SourceSurface contains premultiplied alpha.
968 // If we're abusing it to contain non-premultiplied alpha then we want to
969 // avoid having Moz2D do any conversions on it (like copy to another
970 // surface). Hence why we try to wrap framesurf's data here for
971 // FLAG_DECODE_NO_PREMULTIPLY_ALPHA.
972 if ((aFlags & FLAG_WANT_DATA_SURFACE) != 0 ||
973 (aFlags & FLAG_DECODE_NO_PREMULTIPLY_ALPHA) != 0) {
974 result = gfxPlatform::GetPlatform()->GetWrappedDataSourceSurface(framesurf);
975 }
976 if (!result) {
977 result = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(nullptr,
978 framesurf);
979 }
980 return result.forget();
981 }
982
983 already_AddRefed<layers::Image>
984 RasterImage::GetCurrentImage()
985 {
986 if (!mDecoded) {
987 // We can't call StartDecoding because that can synchronously notify
988 // which can cause DOM modification
989 RequestDecodeCore(ASYNCHRONOUS);
990 return nullptr;
991 }
992
993 RefPtr<SourceSurface> surface = GetFrame(FRAME_CURRENT, FLAG_NONE);
994 if (!surface) {
995 // The OS threw out some or all of our buffer. Start decoding again.
996 // GetFrame will only return null in the case that the image was
997 // discarded. We already checked that the image is decoded, so other
998 // error paths are not possible.
999 ForceDiscard();
1000 RequestDecodeCore(ASYNCHRONOUS);
1001 return nullptr;
1002 }
1003
1004 if (!mImageContainer) {
1005 mImageContainer = LayerManager::CreateImageContainer();
1006 }
1007
1008 CairoImage::Data cairoData;
1009 GetWidth(&cairoData.mSize.width);
1010 GetHeight(&cairoData.mSize.height);
1011 cairoData.mSourceSurface = surface;
1012
1013 nsRefPtr<layers::Image> image = mImageContainer->CreateImage(ImageFormat::CAIRO_SURFACE);
1014 NS_ASSERTION(image, "Failed to create Image");
1015
1016 static_cast<CairoImage*>(image.get())->SetData(cairoData);
1017
1018 return image.forget();
1019 }
1020
1021
1022 NS_IMETHODIMP
1023 RasterImage::GetImageContainer(LayerManager* aManager, ImageContainer **_retval)
1024 {
1025 int32_t maxTextureSize = aManager->GetMaxTextureSize();
1026 if (mSize.width > maxTextureSize || mSize.height > maxTextureSize) {
1027 *_retval = nullptr;
1028 return NS_OK;
1029 }
1030
1031 if (IsUnlocked() && mStatusTracker) {
1032 mStatusTracker->OnUnlockedDraw();
1033 }
1034
1035 if (!mImageContainer) {
1036 mImageContainer = mImageContainerCache;
1037 }
1038
1039 if (mImageContainer) {
1040 *_retval = mImageContainer;
1041 NS_ADDREF(*_retval);
1042 return NS_OK;
1043 }
1044
1045 nsRefPtr<layers::Image> image = GetCurrentImage();
1046 if (!image) {
1047 return NS_ERROR_NOT_AVAILABLE;
1048 }
1049 mImageContainer->SetCurrentImageInTransaction(image);
1050
1051 *_retval = mImageContainer;
1052 NS_ADDREF(*_retval);
1053 // We only need to be careful about holding on to the image when it is
1054 // discardable by the OS.
1055 if (CanForciblyDiscardAndRedecode()) {
1056 mImageContainerCache = mImageContainer->asWeakPtr();
1057 mImageContainer = nullptr;
1058 }
1059
1060 return NS_OK;
1061 }
1062
1063 void
1064 RasterImage::UpdateImageContainer()
1065 {
1066 if (!mImageContainer || IsInUpdateImageContainer()) {
1067 return;
1068 }
1069
1070 SetInUpdateImageContainer(true);
1071
1072 nsRefPtr<layers::Image> image = GetCurrentImage();
1073 if (!image) {
1074 return;
1075 }
1076 mImageContainer->SetCurrentImage(image);
1077 SetInUpdateImageContainer(false);
1078 }
1079
1080 size_t
1081 RasterImage::HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
1082 {
1083 // n == 0 is possible for two reasons.
1084 // - This is a zero-length image.
1085 // - We're on a platform where moz_malloc_size_of always returns 0.
1086 // In either case the fallback works appropriately.
1087 size_t n = mSourceData.SizeOfExcludingThis(aMallocSizeOf);
1088 if (n == 0) {
1089 n = mSourceData.Length();
1090 }
1091 return n;
1092 }
1093
1094 size_t
1095 RasterImage::SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
1096 MallocSizeOf aMallocSizeOf) const
1097 {
1098 size_t n = mFrameBlender.SizeOfDecodedWithComputedFallbackIfHeap(aLocation, aMallocSizeOf);
1099
1100 if (mScaleResult.status == SCALE_DONE) {
1101 n += mScaleResult.frame->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation, aMallocSizeOf);
1102 }
1103
1104 return n;
1105 }
1106
1107 size_t
1108 RasterImage::HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const
1109 {
1110 return SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation::IN_PROCESS_HEAP,
1111 aMallocSizeOf);
1112 }
1113
1114 size_t
1115 RasterImage::NonHeapSizeOfDecoded() const
1116 {
1117 return SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation::IN_PROCESS_NONHEAP,
1118 nullptr);
1119 }
1120
1121 size_t
1122 RasterImage::OutOfProcessSizeOfDecoded() const
1123 {
1124 return SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation::OUT_OF_PROCESS,
1125 nullptr);
1126 }
1127
1128 void
1129 RasterImage::EnsureAnimExists()
1130 {
1131 if (!mAnim) {
1132
1133 // Create the animation context
1134 mAnim = new FrameAnimator(mFrameBlender, mAnimationMode);
1135
1136 // We don't support discarding animated images (See bug 414259).
1137 // Lock the image and throw away the key.
1138 //
1139 // Note that this is inefficient, since we could get rid of the source
1140 // data too. However, doing this is actually hard, because we're probably
1141 // calling ensureAnimExists mid-decode, and thus we're decoding out of
1142 // the source buffer. Since we're going to fix this anyway later, and
1143 // since we didn't kill the source data in the old world either, locking
1144 // is acceptable for the moment.
1145 LockImage();
1146
1147 // Notify our observers that we are starting animation.
1148 nsRefPtr<imgStatusTracker> statusTracker = CurrentStatusTracker();
1149 statusTracker->RecordImageIsAnimated();
1150 }
1151 }
1152
1153 nsresult
1154 RasterImage::InternalAddFrameHelper(uint32_t framenum, imgFrame *aFrame,
1155 uint8_t **imageData, uint32_t *imageLength,
1156 uint32_t **paletteData, uint32_t *paletteLength,
1157 imgFrame** aRetFrame)
1158 {
1159 NS_ABORT_IF_FALSE(framenum <= GetNumFrames(), "Invalid frame index!");
1160 if (framenum > GetNumFrames())
1161 return NS_ERROR_INVALID_ARG;
1162
1163 nsAutoPtr<imgFrame> frame(aFrame);
1164
1165 // We are in the middle of decoding. This will be unlocked when we finish
1166 // decoding or switch to another frame.
1167 frame->LockImageData();
1168
1169 if (paletteData && paletteLength)
1170 frame->GetPaletteData(paletteData, paletteLength);
1171
1172 frame->GetImageData(imageData, imageLength);
1173
1174 *aRetFrame = frame;
1175
1176 mFrameBlender.InsertFrame(framenum, frame.forget());
1177
1178 return NS_OK;
1179 }
1180
1181 nsresult
1182 RasterImage::InternalAddFrame(uint32_t framenum,
1183 int32_t aX, int32_t aY,
1184 int32_t aWidth, int32_t aHeight,
1185 gfxImageFormat aFormat,
1186 uint8_t aPaletteDepth,
1187 uint8_t **imageData,
1188 uint32_t *imageLength,
1189 uint32_t **paletteData,
1190 uint32_t *paletteLength,
1191 imgFrame** aRetFrame)
1192 {
1193 // We assume that we're in the middle of decoding because we unlock the
1194 // previous frame when we create a new frame, and only when decoding do we
1195 // lock frames.
1196 NS_ABORT_IF_FALSE(mDecoder, "Only decoders may add frames!");
1197
1198 NS_ABORT_IF_FALSE(framenum <= GetNumFrames(), "Invalid frame index!");
1199 if (framenum > GetNumFrames())
1200 return NS_ERROR_INVALID_ARG;
1201
1202 nsAutoPtr<imgFrame> frame(new imgFrame());
1203
1204 nsresult rv = frame->Init(aX, aY, aWidth, aHeight, aFormat, aPaletteDepth);
1205 if (!(mSize.width > 0 && mSize.height > 0))
1206 NS_WARNING("Shouldn't call InternalAddFrame with zero size");
1207 if (!NS_SUCCEEDED(rv))
1208 NS_WARNING("imgFrame::Init should succeed");
1209 NS_ENSURE_SUCCESS(rv, rv);
1210
1211 // We know we are in a decoder. Therefore, we must unlock the previous frame
1212 // when we move on to decoding into the next frame.
1213 if (GetNumFrames() > 0) {
1214 imgFrame *prevframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1);
1215 prevframe->UnlockImageData();
1216 }
1217
1218 if (GetNumFrames() == 0) {
1219 return InternalAddFrameHelper(framenum, frame.forget(), imageData, imageLength,
1220 paletteData, paletteLength, aRetFrame);
1221 }
1222
1223 if (GetNumFrames() == 1) {
1224 // Since we're about to add our second frame, initialize animation stuff
1225 EnsureAnimExists();
1226
1227 // If we dispose of the first frame by clearing it, then the
1228 // First Frame's refresh area is all of itself.
1229 // RESTORE_PREVIOUS is invalid (assumed to be DISPOSE_CLEAR)
1230 int32_t frameDisposalMethod = mFrameBlender.RawGetFrame(0)->GetFrameDisposalMethod();
1231 if (frameDisposalMethod == FrameBlender::kDisposeClear ||
1232 frameDisposalMethod == FrameBlender::kDisposeRestorePrevious)
1233 mAnim->SetFirstFrameRefreshArea(mFrameBlender.RawGetFrame(0)->GetRect());
1234 }
1235
1236 // Calculate firstFrameRefreshArea
1237 // Some gifs are huge but only have a small area that they animate
1238 // We only need to refresh that small area when Frame 0 comes around again
1239 mAnim->UnionFirstFrameRefreshArea(frame->GetRect());
1240
1241 rv = InternalAddFrameHelper(framenum, frame.forget(), imageData, imageLength,
1242 paletteData, paletteLength, aRetFrame);
1243
1244 return rv;
1245 }
1246
1247 bool
1248 RasterImage::ApplyDecodeFlags(uint32_t aNewFlags, uint32_t aWhichFrame)
1249 {
1250 if (mFrameDecodeFlags == (aNewFlags & DECODE_FLAGS_MASK))
1251 return true; // Not asking very much of us here.
1252
1253 if (mDecoded) {
1254 // If the requested frame is opaque and the current and new decode flags
1255 // only differ in the premultiply alpha bit then we can use the existing
1256 // frame, we don't need to discard and re-decode.
1257 uint32_t currentNonAlphaFlags =
1258 (mFrameDecodeFlags & DECODE_FLAGS_MASK) & ~FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
1259 uint32_t newNonAlphaFlags =
1260 (aNewFlags & DECODE_FLAGS_MASK) & ~FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
1261 if (currentNonAlphaFlags == newNonAlphaFlags && FrameIsOpaque(aWhichFrame)) {
1262 return true;
1263 }
1264
1265 // if we can't discard, then we're screwed; we have no way
1266 // to re-decode. Similarly if we aren't allowed to do a sync
1267 // decode.
1268 if (!(aNewFlags & FLAG_SYNC_DECODE))
1269 return false;
1270 if (!CanForciblyDiscardAndRedecode())
1271 return false;
1272 ForceDiscard();
1273 }
1274
1275 mFrameDecodeFlags = aNewFlags & DECODE_FLAGS_MASK;
1276 return true;
1277 }
1278
1279 nsresult
1280 RasterImage::SetSize(int32_t aWidth, int32_t aHeight, Orientation aOrientation)
1281 {
1282 MOZ_ASSERT(NS_IsMainThread());
1283 mDecodingMonitor.AssertCurrentThreadIn();
1284
1285 if (mError)
1286 return NS_ERROR_FAILURE;
1287
1288 // Ensure that we have positive values
1289 // XXX - Why isn't the size unsigned? Should this be changed?
1290 if ((aWidth < 0) || (aHeight < 0))
1291 return NS_ERROR_INVALID_ARG;
1292
1293 // if we already have a size, check the new size against the old one
1294 if (!mMultipart && mHasSize &&
1295 ((aWidth != mSize.width) ||
1296 (aHeight != mSize.height) ||
1297 (aOrientation != mOrientation))) {
1298 NS_WARNING("Image changed size on redecode! This should not happen!");
1299
1300 // Make the decoder aware of the error so that it doesn't try to call
1301 // FinishInternal during ShutdownDecoder.
1302 if (mDecoder)
1303 mDecoder->PostResizeError();
1304
1305 DoError();
1306 return NS_ERROR_UNEXPECTED;
1307 }
1308
1309 // Set the size and flag that we have it
1310 mSize.SizeTo(aWidth, aHeight);
1311 mOrientation = aOrientation;
1312 mHasSize = true;
1313
1314 mFrameBlender.SetSize(mSize);
1315
1316 return NS_OK;
1317 }
1318
1319 nsresult
1320 RasterImage::EnsureFrame(uint32_t aFrameNum, int32_t aX, int32_t aY,
1321 int32_t aWidth, int32_t aHeight,
1322 gfxImageFormat aFormat,
1323 uint8_t aPaletteDepth,
1324 uint8_t **imageData, uint32_t *imageLength,
1325 uint32_t **paletteData, uint32_t *paletteLength,
1326 imgFrame** aRetFrame)
1327 {
1328 if (mError)
1329 return NS_ERROR_FAILURE;
1330
1331 NS_ENSURE_ARG_POINTER(imageData);
1332 NS_ENSURE_ARG_POINTER(imageLength);
1333 NS_ENSURE_ARG_POINTER(aRetFrame);
1334 NS_ABORT_IF_FALSE(aFrameNum <= GetNumFrames(), "Invalid frame index!");
1335
1336 if (aPaletteDepth > 0) {
1337 NS_ENSURE_ARG_POINTER(paletteData);
1338 NS_ENSURE_ARG_POINTER(paletteLength);
1339 }
1340
1341 if (aFrameNum > GetNumFrames())
1342 return NS_ERROR_INVALID_ARG;
1343
1344 // Adding a frame that doesn't already exist.
1345 if (aFrameNum == GetNumFrames()) {
1346 return InternalAddFrame(aFrameNum, aX, aY, aWidth, aHeight, aFormat,
1347 aPaletteDepth, imageData, imageLength,
1348 paletteData, paletteLength, aRetFrame);
1349 }
1350
1351 imgFrame *frame = mFrameBlender.RawGetFrame(aFrameNum);
1352 if (!frame) {
1353 return InternalAddFrame(aFrameNum, aX, aY, aWidth, aHeight, aFormat,
1354 aPaletteDepth, imageData, imageLength,
1355 paletteData, paletteLength, aRetFrame);
1356 }
1357
1358 // See if we can re-use the frame that already exists.
1359 nsIntRect rect = frame->GetRect();
1360 if (rect.x == aX && rect.y == aY && rect.width == aWidth &&
1361 rect.height == aHeight && frame->GetFormat() == aFormat &&
1362 frame->GetPaletteDepth() == aPaletteDepth) {
1363 frame->GetImageData(imageData, imageLength);
1364 if (paletteData) {
1365 frame->GetPaletteData(paletteData, paletteLength);
1366 }
1367
1368 *aRetFrame = frame;
1369
1370 // We can re-use the frame if it has image data.
1371 if (*imageData && paletteData && *paletteData) {
1372 return NS_OK;
1373 }
1374 if (*imageData && !paletteData) {
1375 return NS_OK;
1376 }
1377 }
1378
1379 // Not reusable, so replace the frame directly.
1380
1381 // We know this frame is already locked, because it's the one we're currently
1382 // writing to.
1383 frame->UnlockImageData();
1384
1385 mFrameBlender.RemoveFrame(aFrameNum);
1386 nsAutoPtr<imgFrame> newFrame(new imgFrame());
1387 nsresult rv = newFrame->Init(aX, aY, aWidth, aHeight, aFormat, aPaletteDepth);
1388 NS_ENSURE_SUCCESS(rv, rv);
1389 return InternalAddFrameHelper(aFrameNum, newFrame.forget(), imageData,
1390 imageLength, paletteData, paletteLength,
1391 aRetFrame);
1392 }
1393
1394 nsresult
1395 RasterImage::EnsureFrame(uint32_t aFramenum, int32_t aX, int32_t aY,
1396 int32_t aWidth, int32_t aHeight,
1397 gfxImageFormat aFormat,
1398 uint8_t** imageData, uint32_t* imageLength,
1399 imgFrame** aFrame)
1400 {
1401 return EnsureFrame(aFramenum, aX, aY, aWidth, aHeight, aFormat,
1402 /* aPaletteDepth = */ 0, imageData, imageLength,
1403 /* aPaletteData = */ nullptr,
1404 /* aPaletteLength = */ nullptr,
1405 aFrame);
1406 }
1407
1408 nsresult
1409 RasterImage::SetFrameAsNonPremult(uint32_t aFrameNum, bool aIsNonPremult)
1410 {
1411 if (mError)
1412 return NS_ERROR_FAILURE;
1413
1414 NS_ABORT_IF_FALSE(aFrameNum < GetNumFrames(), "Invalid frame index!");
1415 if (aFrameNum >= GetNumFrames())
1416 return NS_ERROR_INVALID_ARG;
1417
1418 imgFrame* frame = mFrameBlender.RawGetFrame(aFrameNum);
1419 NS_ABORT_IF_FALSE(frame, "Calling SetFrameAsNonPremult on frame that doesn't exist!");
1420 NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
1421
1422 frame->SetAsNonPremult(aIsNonPremult);
1423
1424 return NS_OK;
1425 }
1426
1427 nsresult
1428 RasterImage::DecodingComplete()
1429 {
1430 MOZ_ASSERT(NS_IsMainThread());
1431
1432 if (mError)
1433 return NS_ERROR_FAILURE;
1434
1435 // Flag that we're done decoding.
1436 // XXX - these should probably be combined when we fix animated image
1437 // discarding with bug 500402.
1438 mDecoded = true;
1439 mHasBeenDecoded = true;
1440
1441 nsresult rv;
1442
1443 // We now have one of the qualifications for discarding. Re-evaluate.
1444 if (CanDiscard()) {
1445 NS_ABORT_IF_FALSE(!DiscardingActive(),
1446 "We shouldn't have been discardable before this");
1447 rv = DiscardTracker::Reset(&mDiscardTrackerNode);
1448 CONTAINER_ENSURE_SUCCESS(rv);
1449 }
1450
1451 // If there's only 1 frame, optimize it. Optimizing animated images
1452 // is not supported.
1453 //
1454 // We don't optimize the frame for multipart images because we reuse
1455 // the frame.
1456 if ((GetNumFrames() == 1) && !mMultipart) {
1457 // CanForciblyDiscard is used instead of CanForciblyDiscardAndRedecode
1458 // because we know decoding is complete at this point and this is not
1459 // an animation
1460 if (DiscardingEnabled() && CanForciblyDiscard()) {
1461 mFrameBlender.RawGetFrame(0)->SetDiscardable();
1462 }
1463 rv = mFrameBlender.RawGetFrame(0)->Optimize();
1464 NS_ENSURE_SUCCESS(rv, rv);
1465 }
1466
1467 // Double-buffer our frame in the multipart case, since we'll start decoding
1468 // into the first frame again immediately and this produces severe tearing.
1469 if (mMultipart) {
1470 if (GetNumFrames() == 1) {
1471 mMultipartDecodedFrame = mFrameBlender.SwapFrame(GetCurrentFrameIndex(),
1472 mMultipartDecodedFrame);
1473 } else {
1474 // Don't double buffer for animated multipart images. It entails more
1475 // complexity and it's not really needed since we already are smart about
1476 // not displaying the still-decoding frame of an animated image. We may
1477 // have already stored an extra frame, though, so we'll release it here.
1478 delete mMultipartDecodedFrame;
1479 mMultipartDecodedFrame = nullptr;
1480 }
1481 }
1482
1483 if (mAnim) {
1484 mAnim->SetDoneDecoding(true);
1485 }
1486
1487 return NS_OK;
1488 }
1489
1490 NS_IMETHODIMP
1491 RasterImage::SetAnimationMode(uint16_t aAnimationMode)
1492 {
1493 if (mAnim) {
1494 mAnim->SetAnimationMode(aAnimationMode);
1495 }
1496 return SetAnimationModeInternal(aAnimationMode);
1497 }
1498
1499 //******************************************************************************
1500 /* void StartAnimation () */
1501 nsresult
1502 RasterImage::StartAnimation()
1503 {
1504 if (mError)
1505 return NS_ERROR_FAILURE;
1506
1507 NS_ABORT_IF_FALSE(ShouldAnimate(), "Should not animate!");
1508
1509 EnsureAnimExists();
1510
1511 imgFrame* currentFrame = GetCurrentImgFrame();
1512 // A timeout of -1 means we should display this frame forever.
1513 if (currentFrame && mFrameBlender.GetTimeoutForFrame(GetCurrentImgFrameIndex()) < 0) {
1514 mAnimationFinished = true;
1515 return NS_ERROR_ABORT;
1516 }
1517
1518 if (mAnim) {
1519 // We need to set the time that this initial frame was first displayed, as
1520 // this is used in AdvanceFrame().
1521 mAnim->InitAnimationFrameTimeIfNecessary();
1522 }
1523
1524 return NS_OK;
1525 }
1526
1527 //******************************************************************************
1528 /* void stopAnimation (); */
1529 nsresult
1530 RasterImage::StopAnimation()
1531 {
1532 NS_ABORT_IF_FALSE(mAnimating, "Should be animating!");
1533
1534 nsresult rv = NS_OK;
1535 if (mError) {
1536 rv = NS_ERROR_FAILURE;
1537 } else {
1538 mAnim->SetAnimationFrameTime(TimeStamp());
1539 }
1540
1541 mAnimating = false;
1542 return rv;
1543 }
1544
1545 //******************************************************************************
1546 /* void resetAnimation (); */
1547 NS_IMETHODIMP
1548 RasterImage::ResetAnimation()
1549 {
1550 if (mError)
1551 return NS_ERROR_FAILURE;
1552
1553 if (mAnimationMode == kDontAnimMode ||
1554 !mAnim || mAnim->GetCurrentAnimationFrameIndex() == 0)
1555 return NS_OK;
1556
1557 mAnimationFinished = false;
1558
1559 if (mAnimating)
1560 StopAnimation();
1561
1562 mFrameBlender.ResetAnimation();
1563 mAnim->ResetAnimation();
1564
1565 UpdateImageContainer();
1566
1567 // Note - We probably want to kick off a redecode somewhere around here when
1568 // we fix bug 500402.
1569
1570 // Update display
1571 if (mStatusTracker) {
1572 nsIntRect rect = mAnim->GetFirstFrameRefreshArea();
1573 mStatusTracker->FrameChanged(&rect);
1574 }
1575
1576 // Start the animation again. It may not have been running before, if
1577 // mAnimationFinished was true before entering this function.
1578 EvaluateAnimation();
1579
1580 return NS_OK;
1581 }
1582
1583 //******************************************************************************
1584 // [notxpcom] void setAnimationStartTime ([const] in TimeStamp aTime);
1585 NS_IMETHODIMP_(void)
1586 RasterImage::SetAnimationStartTime(const mozilla::TimeStamp& aTime)
1587 {
1588 if (mError || mAnimationMode == kDontAnimMode || mAnimating || !mAnim)
1589 return;
1590
1591 mAnim->SetAnimationFrameTime(aTime);
1592 }
1593
1594 NS_IMETHODIMP_(float)
1595 RasterImage::GetFrameIndex(uint32_t aWhichFrame)
1596 {
1597 MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE, "Invalid argument");
1598 return (aWhichFrame == FRAME_FIRST || !mAnim)
1599 ? 0.0f
1600 : mAnim->GetCurrentAnimationFrameIndex();
1601 }
1602
1603 void
1604 RasterImage::SetLoopCount(int32_t aLoopCount)
1605 {
1606 if (mError)
1607 return;
1608
1609 if (mAnim) {
1610 // No need to set this if we're not an animation
1611 mFrameBlender.SetLoopCount(aLoopCount);
1612 }
1613 }
1614
1615 nsresult
1616 RasterImage::AddSourceData(const char *aBuffer, uint32_t aCount)
1617 {
1618 ReentrantMonitorAutoEnter lock(mDecodingMonitor);
1619
1620 if (mError)
1621 return NS_ERROR_FAILURE;
1622
1623 NS_ENSURE_ARG_POINTER(aBuffer);
1624 nsresult rv = NS_OK;
1625
1626 // We should not call this if we're not initialized
1627 NS_ABORT_IF_FALSE(mInitialized, "Calling AddSourceData() on uninitialized "
1628 "RasterImage!");
1629
1630 // We should not call this if we're already finished adding source data
1631 NS_ABORT_IF_FALSE(!mHasSourceData, "Calling AddSourceData() after calling "
1632 "sourceDataComplete()!");
1633
1634 // This call should come straight from necko - no reentrancy allowed
1635 NS_ABORT_IF_FALSE(!mInDecoder, "Re-entrant call to AddSourceData!");
1636
1637 // Image is already decoded, we shouldn't be getting data, but it could
1638 // be extra garbage data at the end of a file.
1639 if (mDecoded) {
1640 return NS_OK;
1641 }
1642
1643 // Starting a new part's frames, let's clean up before we add any
1644 // This needs to happen just before we start getting EnsureFrame() call(s),
1645 // so that there's no gap for anything to miss us.
1646 if (mMultipart && mBytesDecoded == 0) {
1647 // Our previous state may have been animated, so let's clean up
1648 if (mAnimating)
1649 StopAnimation();
1650 mAnimationFinished = false;
1651 if (mAnim) {
1652 delete mAnim;
1653 mAnim = nullptr;
1654 }
1655 // If there's only one frame, this could cause flickering
1656 int old_frame_count = GetNumFrames();
1657 if (old_frame_count > 1) {
1658 mFrameBlender.ClearFrames();
1659 }
1660 }
1661
1662 // If we're not storing source data and we've previously gotten the size,
1663 // write the data directly to the decoder. (If we haven't gotten the size,
1664 // we'll queue up the data and write it out when we do.)
1665 if (!StoringSourceData() && mHasSize) {
1666 rv = WriteToDecoder(aBuffer, aCount, DECODE_SYNC);
1667 CONTAINER_ENSURE_SUCCESS(rv);
1668
1669 // We're not storing source data, so this data is probably coming straight
1670 // from the network. In this case, we want to display data as soon as we
1671 // get it, so we want to flush invalidations after every write.
1672 nsRefPtr<Decoder> kungFuDeathGrip = mDecoder;
1673 mInDecoder = true;
1674 mDecoder->FlushInvalidations();
1675 mInDecoder = false;
1676
1677 rv = FinishedSomeDecoding();
1678 CONTAINER_ENSURE_SUCCESS(rv);
1679 }
1680
1681 // Otherwise, we're storing data in the source buffer
1682 else {
1683
1684 // Store the data
1685 char *newElem = mSourceData.AppendElements(aBuffer, aCount);
1686 if (!newElem)
1687 return NS_ERROR_OUT_OF_MEMORY;
1688
1689 if (mDecoder) {
1690 DecodePool::Singleton()->RequestDecode(this);
1691 }
1692 }
1693
1694 // Statistics
1695 total_source_bytes += aCount;
1696 if (mDiscardable)
1697 discardable_source_bytes += aCount;
1698 PR_LOG (GetCompressedImageAccountingLog(), PR_LOG_DEBUG,
1699 ("CompressedImageAccounting: Added compressed data to RasterImage %p (%s). "
1700 "Total Containers: %d, Discardable containers: %d, "
1701 "Total source bytes: %lld, Source bytes for discardable containers %lld",
1702 this,
1703 mSourceDataMimeType.get(),
1704 num_containers,
1705 num_discardable_containers,
1706 total_source_bytes,
1707 discardable_source_bytes));
1708
1709 return NS_OK;
1710 }
1711
1712 /* Note! buf must be declared as char buf[9]; */
1713 // just used for logging and hashing the header
1714 static void
1715 get_header_str (char *buf, char *data, size_t data_len)
1716 {
1717 int i;
1718 int n;
1719 static char hex[] = "0123456789abcdef";
1720
1721 n = data_len < 4 ? data_len : 4;
1722
1723 for (i = 0; i < n; i++) {
1724 buf[i * 2] = hex[(data[i] >> 4) & 0x0f];
1725 buf[i * 2 + 1] = hex[data[i] & 0x0f];
1726 }
1727
1728 buf[i * 2] = 0;
1729 }
1730
1731 nsresult
1732 RasterImage::DoImageDataComplete()
1733 {
1734 MOZ_ASSERT(NS_IsMainThread());
1735
1736 if (mError)
1737 return NS_ERROR_FAILURE;
1738
1739 // If we've been called before, ignore. Otherwise, flag that we have everything
1740 if (mHasSourceData)
1741 return NS_OK;
1742 mHasSourceData = true;
1743
1744 // If there's a decoder open, synchronously decode the beginning of the image
1745 // to check for errors and get the image's size. (If we already have the
1746 // image's size, this does nothing.) Then kick off an async decode of the
1747 // rest of the image.
1748 if (mDecoder) {
1749 nsresult rv = DecodePool::Singleton()->DecodeUntilSizeAvailable(this);
1750 CONTAINER_ENSURE_SUCCESS(rv);
1751 }
1752
1753 {
1754 ReentrantMonitorAutoEnter lock(mDecodingMonitor);
1755
1756 // If we're not storing any source data, then there's nothing more we can do
1757 // once we've tried decoding for size.
1758 if (!StoringSourceData() && mDecoder) {
1759 nsresult rv = ShutdownDecoder(eShutdownIntent_Done);
1760 CONTAINER_ENSURE_SUCCESS(rv);
1761 }
1762
1763 // If DecodeUntilSizeAvailable didn't finish the decode, let the decode worker
1764 // finish decoding this image.
1765 if (mDecoder) {
1766 DecodePool::Singleton()->RequestDecode(this);
1767 }
1768
1769 // Free up any extra space in the backing buffer
1770 mSourceData.Compact();
1771 }
1772
1773 // Log header information
1774 if (PR_LOG_TEST(GetCompressedImageAccountingLog(), PR_LOG_DEBUG)) {
1775 char buf[9];
1776 get_header_str(buf, mSourceData.Elements(), mSourceData.Length());
1777 PR_LOG (GetCompressedImageAccountingLog(), PR_LOG_DEBUG,
1778 ("CompressedImageAccounting: RasterImage::SourceDataComplete() - data "
1779 "is done for container %p (%s) - header %p is 0x%s (length %d)",
1780 this,
1781 mSourceDataMimeType.get(),
1782 mSourceData.Elements(),
1783 buf,
1784 mSourceData.Length()));
1785 }
1786
1787 // We now have one of the qualifications for discarding. Re-evaluate.
1788 if (CanDiscard()) {
1789 nsresult rv = DiscardTracker::Reset(&mDiscardTrackerNode);
1790 CONTAINER_ENSURE_SUCCESS(rv);
1791 }
1792 return NS_OK;
1793 }
1794
1795 nsresult
1796 RasterImage::OnImageDataComplete(nsIRequest*, nsISupports*, nsresult aStatus, bool aLastPart)
1797 {
1798 nsresult finalStatus = DoImageDataComplete();
1799
1800 // Give precedence to Necko failure codes.
1801 if (NS_FAILED(aStatus))
1802 finalStatus = aStatus;
1803
1804 // We just recorded OnStopRequest; we need to inform our listeners.
1805 {
1806 ReentrantMonitorAutoEnter lock(mDecodingMonitor);
1807
1808 nsRefPtr<imgStatusTracker> statusTracker = CurrentStatusTracker();
1809 statusTracker->GetDecoderObserver()->OnStopRequest(aLastPart, finalStatus);
1810
1811 FinishedSomeDecoding();
1812 }
1813
1814 return finalStatus;
1815 }
1816
1817 nsresult
1818 RasterImage::OnImageDataAvailable(nsIRequest*,
1819 nsISupports*,
1820 nsIInputStream* aInStr,
1821 uint64_t,
1822 uint32_t aCount)
1823 {
1824 nsresult rv;
1825
1826 // WriteToRasterImage always consumes everything it gets
1827 // if it doesn't run out of memory
1828 uint32_t bytesRead;
1829 rv = aInStr->ReadSegments(WriteToRasterImage, this, aCount, &bytesRead);
1830
1831 NS_ABORT_IF_FALSE(bytesRead == aCount || HasError(),
1832 "WriteToRasterImage should consume everything or the image must be in error!");
1833
1834 return rv;
1835 }
1836
1837 nsresult
1838 RasterImage::OnNewSourceData()
1839 {
1840 MOZ_ASSERT(NS_IsMainThread());
1841
1842 nsresult rv;
1843
1844 if (mError)
1845 return NS_ERROR_FAILURE;
1846
1847 // The source data should be complete before calling this
1848 NS_ABORT_IF_FALSE(mHasSourceData,
1849 "Calling NewSourceData before SourceDataComplete!");
1850 if (!mHasSourceData)
1851 return NS_ERROR_ILLEGAL_VALUE;
1852
1853 // Only supported for multipart channels. It wouldn't be too hard to change this,
1854 // but it would involve making sure that things worked for decode-on-draw and
1855 // discarding. Presently there's no need for this, so we don't.
1856 NS_ABORT_IF_FALSE(mMultipart, "NewSourceData only supported for multipart");
1857 if (!mMultipart)
1858 return NS_ERROR_ILLEGAL_VALUE;
1859
1860 // We're multipart, so we shouldn't be storing source data
1861 NS_ABORT_IF_FALSE(!StoringSourceData(),
1862 "Shouldn't be storing source data for multipart");
1863
1864 // We're not storing the source data and we got SourceDataComplete. We should
1865 // have shut down the previous decoder
1866 NS_ABORT_IF_FALSE(!mDecoder, "Shouldn't have a decoder in NewSourceData");
1867
1868 // The decoder was shut down and we didn't flag an error, so we should be decoded
1869 NS_ABORT_IF_FALSE(mDecoded, "Should be decoded in NewSourceData");
1870
1871 // Reset some flags
1872 mDecoded = false;
1873 mHasSourceData = false;
1874 mHasSize = false;
1875 mWantFullDecode = true;
1876 mDecodeRequest = nullptr;
1877
1878 if (mAnim) {
1879 mAnim->SetDoneDecoding(false);
1880 }
1881
1882 // We always need the size first.
1883 rv = InitDecoder(/* aDoSizeDecode = */ true);
1884 CONTAINER_ENSURE_SUCCESS(rv);
1885
1886 return NS_OK;
1887 }
1888
1889 nsresult
1890 RasterImage::SetSourceSizeHint(uint32_t sizeHint)
1891 {
1892 if (sizeHint && StoringSourceData())
1893 return mSourceData.SetCapacity(sizeHint) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
1894 return NS_OK;
1895 }
1896
1897 /********* Methods to implement lazy allocation of nsIProperties object *************/
1898 NS_IMETHODIMP
1899 RasterImage::Get(const char *prop, const nsIID & iid, void * *result)
1900 {
1901 if (!mProperties)
1902 return NS_ERROR_FAILURE;
1903 return mProperties->Get(prop, iid, result);
1904 }
1905
1906 NS_IMETHODIMP
1907 RasterImage::Set(const char *prop, nsISupports *value)
1908 {
1909 if (!mProperties)
1910 mProperties = do_CreateInstance("@mozilla.org/properties;1");
1911 if (!mProperties)
1912 return NS_ERROR_OUT_OF_MEMORY;
1913 return mProperties->Set(prop, value);
1914 }
1915
1916 NS_IMETHODIMP
1917 RasterImage::Has(const char *prop, bool *_retval)
1918 {
1919 NS_ENSURE_ARG_POINTER(_retval);
1920 if (!mProperties) {
1921 *_retval = false;
1922 return NS_OK;
1923 }
1924 return mProperties->Has(prop, _retval);
1925 }
1926
1927 NS_IMETHODIMP
1928 RasterImage::Undefine(const char *prop)
1929 {
1930 if (!mProperties)
1931 return NS_ERROR_FAILURE;
1932 return mProperties->Undefine(prop);
1933 }
1934
1935 NS_IMETHODIMP
1936 RasterImage::GetKeys(uint32_t *count, char ***keys)
1937 {
1938 if (!mProperties) {
1939 *count = 0;
1940 *keys = nullptr;
1941 return NS_OK;
1942 }
1943 return mProperties->GetKeys(count, keys);
1944 }
1945
1946 void
1947 RasterImage::Discard(bool force)
1948 {
1949 MOZ_ASSERT(NS_IsMainThread());
1950
1951 // We should be ok for discard
1952 NS_ABORT_IF_FALSE(force ? CanForciblyDiscard() : CanDiscard(), "Asked to discard but can't!");
1953
1954 // We should never discard when we have an active decoder
1955 NS_ABORT_IF_FALSE(!mDecoder, "Asked to discard with open decoder!");
1956
1957 // As soon as an image becomes animated, it becomes non-discardable and any
1958 // timers are cancelled.
1959 NS_ABORT_IF_FALSE(!mAnim, "Asked to discard for animated image!");
1960
1961 // For post-operation logging
1962 int old_frame_count = GetNumFrames();
1963
1964 // Delete all the decoded frames
1965 mFrameBlender.Discard();
1966
1967 // Clear our downscaled frame.
1968 mScaleResult.status = SCALE_INVALID;
1969 mScaleResult.frame = nullptr;
1970
1971 // Clear the last decoded multipart frame.
1972 delete mMultipartDecodedFrame;
1973 mMultipartDecodedFrame = nullptr;
1974
1975 // Flag that we no longer have decoded frames for this image
1976 mDecoded = false;
1977
1978 // Notify that we discarded
1979 if (mStatusTracker)
1980 mStatusTracker->OnDiscard();
1981
1982 mDecodeRequest = nullptr;
1983
1984 if (force)
1985 DiscardTracker::Remove(&mDiscardTrackerNode);
1986
1987 // Log
1988 PR_LOG(GetCompressedImageAccountingLog(), PR_LOG_DEBUG,
1989 ("CompressedImageAccounting: discarded uncompressed image "
1990 "data from RasterImage %p (%s) - %d frames (cached count: %d); "
1991 "Total Containers: %d, Discardable containers: %d, "
1992 "Total source bytes: %lld, Source bytes for discardable containers %lld",
1993 this,
1994 mSourceDataMimeType.get(),
1995 old_frame_count,
1996 GetNumFrames(),
1997 num_containers,
1998 num_discardable_containers,
1999 total_source_bytes,
2000 discardable_source_bytes));
2001 }
2002
2003 // Helper method to determine if we can discard an image
2004 bool
2005 RasterImage::CanDiscard() {
2006 return (DiscardingEnabled() && // Globally enabled...
2007 mDiscardable && // ...Enabled at creation time...
2008 (mLockCount == 0) && // ...not temporarily disabled...
2009 mHasSourceData && // ...have the source data...
2010 mDecoded); // ...and have something to discard.
2011 }
2012
2013 bool
2014 RasterImage::CanForciblyDiscard() {
2015 return mDiscardable && // ...Enabled at creation time...
2016 mHasSourceData; // ...have the source data...
2017 }
2018
2019 bool
2020 RasterImage::CanForciblyDiscardAndRedecode() {
2021 return mDiscardable && // ...Enabled at creation time...
2022 mHasSourceData && // ...have the source data...
2023 !mDecoder && // Can't discard with an open decoder
2024 !mAnim; // Can never discard animated images
2025 }
2026
2027 // Helper method to tell us whether the clock is currently running for
2028 // discarding this image. Mainly for assertions.
2029 bool
2030 RasterImage::DiscardingActive() {
2031 return mDiscardTrackerNode.isInList();
2032 }
2033
2034 // Helper method to determine if we're storing the source data in a buffer
2035 // or just writing it directly to the decoder
2036 bool
2037 RasterImage::StoringSourceData() const {
2038 return (mDecodeOnDraw || mDiscardable);
2039 }
2040
2041
2042 // Sets up a decoder for this image. It is an error to call this function
2043 // when decoding is already in process (ie - when mDecoder is non-null).
2044 nsresult
2045 RasterImage::InitDecoder(bool aDoSizeDecode)
2046 {
2047 // Ensure that the decoder is not already initialized
2048 NS_ABORT_IF_FALSE(!mDecoder, "Calling InitDecoder() while already decoding!");
2049
2050 // We shouldn't be firing up a decoder if we already have the frames decoded
2051 NS_ABORT_IF_FALSE(!mDecoded, "Calling InitDecoder() but already decoded!");
2052
2053 // Since we're not decoded, we should not have a discard timer active
2054 NS_ABORT_IF_FALSE(!DiscardingActive(), "Discard Timer active in InitDecoder()!");
2055
2056 // Make sure we actually get size before doing a full decode.
2057 if (!aDoSizeDecode) {
2058 NS_ABORT_IF_FALSE(mHasSize, "Must do a size decode before a full decode!");
2059 }
2060
2061 // Figure out which decoder we want
2062 eDecoderType type = GetDecoderType(mSourceDataMimeType.get());
2063 CONTAINER_ENSURE_TRUE(type != eDecoderType_unknown, NS_IMAGELIB_ERROR_NO_DECODER);
2064
2065 // Instantiate the appropriate decoder
2066 switch (type) {
2067 case eDecoderType_png:
2068 mDecoder = new nsPNGDecoder(*this);
2069 break;
2070 case eDecoderType_gif:
2071 mDecoder = new nsGIFDecoder2(*this);
2072 break;
2073 case eDecoderType_jpeg:
2074 // If we have all the data we don't want to waste cpu time doing
2075 // a progressive decode
2076 mDecoder = new nsJPEGDecoder(*this,
2077 mHasBeenDecoded ? Decoder::SEQUENTIAL :
2078 Decoder::PROGRESSIVE);
2079 break;
2080 case eDecoderType_bmp:
2081 mDecoder = new nsBMPDecoder(*this);
2082 break;
2083 case eDecoderType_ico:
2084 mDecoder = new nsICODecoder(*this);
2085 break;
2086 case eDecoderType_icon:
2087 mDecoder = new nsIconDecoder(*this);
2088 break;
2089 default:
2090 NS_ABORT_IF_FALSE(0, "Shouldn't get here!");
2091 }
2092
2093 // If we already have frames, we're probably in the multipart/x-mixed-replace
2094 // case. Regardless, we need to lock the last frame. Our invariant is that,
2095 // while we have a decoder open, the last frame is always locked.
2096 if (GetNumFrames() > 0) {
2097 imgFrame *curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1);
2098 curframe->LockImageData();
2099 }
2100
2101 // Initialize the decoder
2102 if (!mDecodeRequest) {
2103 mDecodeRequest = new DecodeRequest(this);
2104 }
2105 MOZ_ASSERT(mDecodeRequest->mStatusTracker);
2106 MOZ_ASSERT(mDecodeRequest->mStatusTracker->GetDecoderObserver());
2107 mDecoder->SetObserver(mDecodeRequest->mStatusTracker->GetDecoderObserver());
2108 mDecoder->SetSizeDecode(aDoSizeDecode);
2109 mDecoder->SetDecodeFlags(mFrameDecodeFlags);
2110 if (!aDoSizeDecode) {
2111 // We already have the size; tell the decoder so it can preallocate a
2112 // frame. By default, we create an ARGB frame with no offset. If decoders
2113 // need a different type, they need to ask for it themselves.
2114 mDecoder->NeedNewFrame(0, 0, 0, mSize.width, mSize.height,
2115 gfxImageFormat::ARGB32);
2116 mDecoder->AllocateFrame();
2117 }
2118 mDecoder->Init();
2119 CONTAINER_ENSURE_SUCCESS(mDecoder->GetDecoderError());
2120
2121 if (!aDoSizeDecode) {
2122 Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Subtract(mDecodeCount);
2123 mDecodeCount++;
2124 Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(mDecodeCount);
2125
2126 if (mDecodeCount > sMaxDecodeCount) {
2127 // Don't subtract out 0 from the histogram, because that causes its count
2128 // to go negative, which is not kosher.
2129 if (sMaxDecodeCount > 0) {
2130 Telemetry::GetHistogramById(Telemetry::IMAGE_MAX_DECODE_COUNT)->Subtract(sMaxDecodeCount);
2131 }
2132 sMaxDecodeCount = mDecodeCount;
2133 Telemetry::GetHistogramById(Telemetry::IMAGE_MAX_DECODE_COUNT)->Add(sMaxDecodeCount);
2134 }
2135 }
2136
2137 return NS_OK;
2138 }
2139
2140 // Flushes, closes, and nulls-out a decoder. Cleans up any related decoding
2141 // state. It is an error to call this function when there is no initialized
2142 // decoder.
2143 //
2144 // aIntent specifies the intent of the shutdown. If aIntent is
2145 // eShutdownIntent_Done, an error is flagged if we didn't get what we should
2146 // have out of the decode. If aIntent is eShutdownIntent_NotNeeded, we don't
2147 // check this. If aIntent is eShutdownIntent_Error, we shut down in error mode.
2148 nsresult
2149 RasterImage::ShutdownDecoder(eShutdownIntent aIntent)
2150 {
2151 MOZ_ASSERT(NS_IsMainThread());
2152 mDecodingMonitor.AssertCurrentThreadIn();
2153
2154 // Ensure that our intent is valid
2155 NS_ABORT_IF_FALSE((aIntent >= 0) && (aIntent < eShutdownIntent_AllCount),
2156 "Invalid shutdown intent");
2157
2158 // Ensure that the decoder is initialized
2159 NS_ABORT_IF_FALSE(mDecoder, "Calling ShutdownDecoder() with no active decoder!");
2160
2161 // Figure out what kind of decode we were doing before we get rid of our decoder
2162 bool wasSizeDecode = mDecoder->IsSizeDecode();
2163
2164 // Finalize the decoder
2165 // null out mDecoder, _then_ check for errors on the close (otherwise the
2166 // error routine might re-invoke ShutdownDecoder)
2167 nsRefPtr<Decoder> decoder = mDecoder;
2168 mDecoder = nullptr;
2169
2170 mFinishing = true;
2171 mInDecoder = true;
2172 decoder->Finish(aIntent);
2173 mInDecoder = false;
2174 mFinishing = false;
2175
2176 // Unlock the last frame (if we have any). Our invariant is that, while we
2177 // have a decoder open, the last frame is always locked.
2178 if (GetNumFrames() > 0) {
2179 imgFrame *curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1);
2180 curframe->UnlockImageData();
2181 }
2182
2183 // Kill off our decode request, if it's pending. (If not, this call is
2184 // harmless.)
2185 DecodePool::StopDecoding(this);
2186
2187 nsresult decoderStatus = decoder->GetDecoderError();
2188 if (NS_FAILED(decoderStatus)) {
2189 DoError();
2190 return decoderStatus;
2191 }
2192
2193 // We just shut down the decoder. If we didn't get what we want, but expected
2194 // to, flag an error
2195 bool failed = false;
2196 if (wasSizeDecode && !mHasSize)
2197 failed = true;
2198 if (!wasSizeDecode && !mDecoded)
2199 failed = true;
2200 if ((aIntent == eShutdownIntent_Done) && failed) {
2201 DoError();
2202 return NS_ERROR_FAILURE;
2203 }
2204
2205 // If we finished a full decode, and we're not meant to be storing source
2206 // data, stop storing it.
2207 if (!wasSizeDecode && !StoringSourceData()) {
2208 mSourceData.Clear();
2209 }
2210
2211 mBytesDecoded = 0;
2212
2213 return NS_OK;
2214 }
2215
2216 // Writes the data to the decoder, updating the total number of bytes written.
2217 nsresult
2218 RasterImage::WriteToDecoder(const char *aBuffer, uint32_t aCount, DecodeStrategy aStrategy)
2219 {
2220 mDecodingMonitor.AssertCurrentThreadIn();
2221
2222 // We should have a decoder
2223 NS_ABORT_IF_FALSE(mDecoder, "Trying to write to null decoder!");
2224
2225 // Write
2226 nsRefPtr<Decoder> kungFuDeathGrip = mDecoder;
2227 mInDecoder = true;
2228 mDecoder->Write(aBuffer, aCount, aStrategy);
2229 mInDecoder = false;
2230
2231 CONTAINER_ENSURE_SUCCESS(mDecoder->GetDecoderError());
2232
2233 // Keep track of the total number of bytes written over the lifetime of the
2234 // decoder
2235 mBytesDecoded += aCount;
2236
2237 return NS_OK;
2238 }
2239
2240 // This function is called in situations where it's clear that we want the
2241 // frames in decoded form (Draw, GetFrame, etc). If we're completely decoded,
2242 // this method resets the discard timer (if we're discardable), since wanting
2243 // the frames now is a good indicator of wanting them again soon. If we're not
2244 // decoded, this method kicks off asynchronous decoding to generate the frames.
2245 nsresult
2246 RasterImage::WantDecodedFrames()
2247 {
2248 nsresult rv;
2249
2250 // If we can discard, the clock should be running. Reset it.
2251 if (CanDiscard()) {
2252 NS_ABORT_IF_FALSE(DiscardingActive(),
2253 "Decoded and discardable but discarding not activated!");
2254 rv = DiscardTracker::Reset(&mDiscardTrackerNode);
2255 CONTAINER_ENSURE_SUCCESS(rv);
2256 }
2257
2258 // Request a decode (no-op if we're decoded)
2259 return StartDecoding();
2260 }
2261
2262 //******************************************************************************
2263 /* void requestDecode() */
2264 NS_IMETHODIMP
2265 RasterImage::RequestDecode()
2266 {
2267 return RequestDecodeCore(SYNCHRONOUS_NOTIFY);
2268 }
2269
2270 /* void startDecode() */
2271 NS_IMETHODIMP
2272 RasterImage::StartDecoding()
2273 {
2274 if (!NS_IsMainThread()) {
2275 return NS_DispatchToMainThread(
2276 NS_NewRunnableMethod(this, &RasterImage::StartDecoding));
2277 }
2278 // Here we are explicitly trading off flashing for responsiveness in the case
2279 // that we're redecoding an image (see bug 845147).
2280 return RequestDecodeCore(mHasBeenDecoded ?
2281 SYNCHRONOUS_NOTIFY : SYNCHRONOUS_NOTIFY_AND_SOME_DECODE);
2282 }
2283
2284 bool
2285 RasterImage::IsDecoded()
2286 {
2287 return mDecoded || mError;
2288 }
2289
2290 NS_IMETHODIMP
2291 RasterImage::RequestDecodeCore(RequestDecodeType aDecodeType)
2292 {
2293 MOZ_ASSERT(NS_IsMainThread());
2294
2295 nsresult rv;
2296
2297 if (mError)
2298 return NS_ERROR_FAILURE;
2299
2300 // If we're already decoded, there's nothing to do.
2301 if (mDecoded)
2302 return NS_OK;
2303
2304 // mFinishing protects against the case when we enter RequestDecode from
2305 // ShutdownDecoder -- in that case, we're done with the decode, we're just
2306 // not quite ready to admit it. See bug 744309.
2307 if (mFinishing)
2308 return NS_OK;
2309
2310 // If we're currently waiting for a new frame, we can't do anything until
2311 // that frame is allocated.
2312 if (mDecoder && mDecoder->NeedsNewFrame())
2313 return NS_OK;
2314
2315 // If our callstack goes through a size decoder, we have a problem.
2316 // We need to shutdown the size decode and replace it with a full
2317 // decoder, but can't do that from within the decoder itself. Thus, we post
2318 // an asynchronous event to the event loop to do it later. Since
2319 // RequestDecode() is an asynchronous function this works fine (though it's
2320 // a little slower).
2321 if (mInDecoder) {
2322 nsRefPtr<imgDecodeRequestor> requestor = new imgDecodeRequestor(*this);
2323 return NS_DispatchToCurrentThread(requestor);
2324 }
2325
2326 // If we have a size decoder open, make sure we get the size
2327 if (mDecoder && mDecoder->IsSizeDecode()) {
2328 nsresult rv = DecodePool::Singleton()->DecodeUntilSizeAvailable(this);
2329 CONTAINER_ENSURE_SUCCESS(rv);
2330
2331 // If we didn't get the size out of the image, we won't until we get more
2332 // data, so signal that we want a full decode and give up for now.
2333 if (!mHasSize) {
2334 mWantFullDecode = true;
2335 return NS_OK;
2336 }
2337 }
2338
2339 ReentrantMonitorAutoEnter lock(mDecodingMonitor);
2340
2341 // If we don't have any bytes to flush to the decoder, we can't do anything.
2342 // mBytesDecoded can be bigger than mSourceData.Length() if we're not storing
2343 // the source data.
2344 if (mBytesDecoded > mSourceData.Length())
2345 return NS_OK;
2346
2347 // If the image is waiting for decode work to be notified, go ahead and do that.
2348 if (mDecodeRequest &&
2349 mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_WORK_DONE &&
2350 aDecodeType != ASYNCHRONOUS) {
2351 nsresult rv = FinishedSomeDecoding();
2352 CONTAINER_ENSURE_SUCCESS(rv);
2353 }
2354
2355 // If we're fully decoded, we have nothing to do. We need this check after
2356 // DecodeUntilSizeAvailable and FinishedSomeDecoding because they can result
2357 // in us finishing an in-progress decode (or kicking off and finishing a
2358 // synchronous decode if we're already waiting on a full decode).
2359 if (mDecoded) {
2360 return NS_OK;
2361 }
2362
2363 // If we've already got a full decoder running, and have already
2364 // decoded some bytes, we have nothing to do
2365 if (mDecoder && !mDecoder->IsSizeDecode() && mBytesDecoded) {
2366 return NS_OK;
2367 }
2368
2369 // If we have a size decode open, interrupt it and shut it down; or if
2370 // the decoder has different flags than what we need
2371 if (mDecoder && mDecoder->GetDecodeFlags() != mFrameDecodeFlags) {
2372 nsresult rv = FinishedSomeDecoding(eShutdownIntent_NotNeeded);
2373 CONTAINER_ENSURE_SUCCESS(rv);
2374 }
2375
2376 // If we don't have a decoder, create one
2377 if (!mDecoder) {
2378 rv = InitDecoder(/* aDoSizeDecode = */ false);
2379 CONTAINER_ENSURE_SUCCESS(rv);
2380
2381 rv = FinishedSomeDecoding();
2382 CONTAINER_ENSURE_SUCCESS(rv);
2383
2384 MOZ_ASSERT(mDecoder);
2385 }
2386
2387 // If we've read all the data we have, we're done
2388 if (mHasSourceData && mBytesDecoded == mSourceData.Length())
2389 return NS_OK;
2390
2391 // If we can do decoding now, do so. Small images will decode completely,
2392 // large images will decode a bit and post themselves to the event loop
2393 // to finish decoding.
2394 if (!mDecoded && !mInDecoder && mHasSourceData && aDecodeType == SYNCHRONOUS_NOTIFY_AND_SOME_DECODE) {
2395 PROFILER_LABEL_PRINTF("RasterImage", "DecodeABitOf", "%s", GetURIString().get());
2396 DecodePool::Singleton()->DecodeABitOf(this, DECODE_SYNC);
2397 return NS_OK;
2398 }
2399
2400 if (!mDecoded) {
2401 // If we get this far, dispatch the worker. We do this instead of starting
2402 // any immediate decoding to guarantee that all our decode notifications are
2403 // dispatched asynchronously, and to ensure we stay responsive.
2404 DecodePool::Singleton()->RequestDecode(this);
2405 }
2406
2407 return NS_OK;
2408 }
2409
2410 // Synchronously decodes as much data as possible
2411 nsresult
2412 RasterImage::SyncDecode()
2413 {
2414 PROFILER_LABEL_PRINTF("RasterImage", "SyncDecode", "%s", GetURIString().get());;
2415
2416 // If we have a size decoder open, make sure we get the size
2417 if (mDecoder && mDecoder->IsSizeDecode()) {
2418 nsresult rv = DecodePool::Singleton()->DecodeUntilSizeAvailable(this);
2419 CONTAINER_ENSURE_SUCCESS(rv);
2420
2421 // If we didn't get the size out of the image, we won't until we get more
2422 // data, so signal that we want a full decode and give up for now.
2423 if (!mHasSize) {
2424 mWantFullDecode = true;
2425 return NS_ERROR_NOT_AVAILABLE;
2426 }
2427 }
2428
2429 ReentrantMonitorAutoEnter lock(mDecodingMonitor);
2430
2431 // We really have no good way of forcing a synchronous decode if we're being
2432 // called in a re-entrant manner (ie, from an event listener fired by a
2433 // decoder), because the decoding machinery is already tied up. We thus explicitly
2434 // disallow this type of call in the API, and check for it in API methods.
2435 NS_ABORT_IF_FALSE(!mInDecoder, "Yikes, forcing sync in reentrant call!");
2436
2437 if (mDecodeRequest) {
2438 // If the image is waiting for decode work to be notified, go ahead and do that.
2439 if (mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_WORK_DONE) {
2440 nsresult rv = FinishedSomeDecoding();
2441 CONTAINER_ENSURE_SUCCESS(rv);
2442 }
2443 }
2444
2445 nsresult rv;
2446
2447 // If we're decoded already, or decoding until the size was available
2448 // finished us as a side-effect, no worries
2449 if (mDecoded)
2450 return NS_OK;
2451
2452 // If we don't have any bytes to flush to the decoder, we can't do anything.
2453 // mBytesDecoded can be bigger than mSourceData.Length() if we're not storing
2454 // the source data.
2455 if (mBytesDecoded > mSourceData.Length())
2456 return NS_OK;
2457
2458 // If we have a decoder open with different flags than what we need, shut it
2459 // down
2460 if (mDecoder && mDecoder->GetDecodeFlags() != mFrameDecodeFlags) {
2461 nsresult rv = FinishedSomeDecoding(eShutdownIntent_NotNeeded);
2462 CONTAINER_ENSURE_SUCCESS(rv);
2463
2464 if (mDecoded) {
2465 // If we've finished decoding we need to discard so we can re-decode
2466 // with the new flags. If we can't discard then there isn't
2467 // anything we can do.
2468 if (!CanForciblyDiscardAndRedecode())
2469 return NS_ERROR_NOT_AVAILABLE;
2470 ForceDiscard();
2471 }
2472 }
2473
2474 // If we're currently waiting on a new frame for this image, we have to create
2475 // it now.
2476 if (mDecoder && mDecoder->NeedsNewFrame()) {
2477 mDecoder->AllocateFrame();
2478 mDecodeRequest->mAllocatedNewFrame = true;
2479 }
2480
2481 // If we don't have a decoder, create one
2482 if (!mDecoder) {
2483 rv = InitDecoder(/* aDoSizeDecode = */ false);
2484 CONTAINER_ENSURE_SUCCESS(rv);
2485 }
2486
2487 // Write everything we have
2488 rv = DecodeSomeData(mSourceData.Length() - mBytesDecoded, DECODE_SYNC);
2489 CONTAINER_ENSURE_SUCCESS(rv);
2490
2491 // When we're doing a sync decode, we want to get as much information from the
2492 // image as possible. We've send the decoder all of our data, so now's a good
2493 // time to flush any invalidations (in case we don't have all the data and what
2494 // we got left us mid-frame).
2495 nsRefPtr<Decoder> kungFuDeathGrip = mDecoder;
2496 mInDecoder = true;
2497 mDecoder->FlushInvalidations();
2498 mInDecoder = false;
2499
2500 rv = FinishedSomeDecoding();
2501 CONTAINER_ENSURE_SUCCESS(rv);
2502
2503 // If our decoder's still open, there's still work to be done.
2504 if (mDecoder) {
2505 DecodePool::Singleton()->RequestDecode(this);
2506 }
2507
2508 // All good if no errors!
2509 return mError ? NS_ERROR_FAILURE : NS_OK;
2510 }
2511
2512 bool
2513 RasterImage::CanQualityScale(const gfxSize& scale)
2514 {
2515 // If target size is 1:1 with original, don't scale.
2516 if (scale.width == 1.0 && scale.height == 1.0)
2517 return false;
2518
2519 // To save memory don't quality upscale images bigger than the limit.
2520 if (scale.width > 1.0 || scale.height > 1.0) {
2521 uint32_t scaled_size = static_cast<uint32_t>(mSize.width * mSize.height * scale.width * scale.height);
2522 if (scaled_size > gHQUpscalingMaxSize)
2523 return false;
2524 }
2525
2526 return true;
2527 }
2528
2529 bool
2530 RasterImage::CanScale(GraphicsFilter aFilter,
2531 gfxSize aScale, uint32_t aFlags)
2532 {
2533 // The high-quality scaler requires Skia.
2534 #ifdef MOZ_ENABLE_SKIA
2535 // We don't use the scaler for animated or multipart images to avoid doing a
2536 // bunch of work on an image that just gets thrown away.
2537 // We only use the scaler when drawing to the window because, if we're not
2538 // drawing to a window (eg a canvas), updates to that image will be ignored.
2539 if (gHQDownscaling && aFilter == GraphicsFilter::FILTER_GOOD &&
2540 !mAnim && mDecoded && !mMultipart && CanQualityScale(aScale) &&
2541 (aFlags & imgIContainer::FLAG_HIGH_QUALITY_SCALING)) {
2542 gfxFloat factor = gHQDownscalingMinFactor / 1000.0;
2543
2544 return (aScale.width < factor || aScale.height < factor);
2545 }
2546 #endif
2547
2548 return false;
2549 }
2550
2551 void
2552 RasterImage::ScalingStart(ScaleRequest* request)
2553 {
2554 MOZ_ASSERT(request);
2555 mScaleResult.scale = request->scale;
2556 mScaleResult.status = SCALE_PENDING;
2557 mScaleRequest = request;
2558 }
2559
2560 void
2561 RasterImage::ScalingDone(ScaleRequest* request, ScaleStatus status)
2562 {
2563 MOZ_ASSERT(status == SCALE_DONE || status == SCALE_INVALID);
2564 MOZ_ASSERT(request);
2565
2566 if (status == SCALE_DONE) {
2567 MOZ_ASSERT(request->done);
2568
2569 imgFrame *scaledFrame = request->dstFrame.forget();
2570 scaledFrame->ImageUpdated(scaledFrame->GetRect());
2571 scaledFrame->ApplyDirtToSurfaces();
2572
2573 if (mStatusTracker) {
2574 mStatusTracker->FrameChanged(&request->srcRect);
2575 }
2576
2577 mScaleResult.status = SCALE_DONE;
2578 mScaleResult.frame = scaledFrame;
2579 mScaleResult.scale = request->scale;
2580 } else {
2581 mScaleResult.status = SCALE_INVALID;
2582 mScaleResult.frame = nullptr;
2583 }
2584
2585 // If we were waiting for this scale to come through, forget the scale
2586 // request. Otherwise, we still have a scale outstanding that it's possible
2587 // for us to (want to) stop.
2588 if (mScaleRequest == request) {
2589 mScaleRequest = nullptr;
2590 }
2591 }
2592
2593 bool
2594 RasterImage::DrawWithPreDownscaleIfNeeded(imgFrame *aFrame,
2595 gfxContext *aContext,
2596 GraphicsFilter aFilter,
2597 const gfxMatrix &aUserSpaceToImageSpace,
2598 const gfxRect &aFill,
2599 const nsIntRect &aSubimage,
2600 uint32_t aFlags)
2601 {
2602 imgFrame *frame = aFrame;
2603 nsIntRect framerect = frame->GetRect();
2604 gfxMatrix userSpaceToImageSpace = aUserSpaceToImageSpace;
2605 gfxMatrix imageSpaceToUserSpace = aUserSpaceToImageSpace;
2606 imageSpaceToUserSpace.Invert();
2607 gfxSize scale = imageSpaceToUserSpace.ScaleFactors(true);
2608 nsIntRect subimage = aSubimage;
2609 nsRefPtr<gfxASurface> surf;
2610
2611 if (CanScale(aFilter, scale, aFlags) && !frame->IsSinglePixel()) {
2612 // If scale factor is still the same that we scaled for and
2613 // ScaleWorker isn't still working, then we can use pre-downscaled frame.
2614 // If scale factor has changed, order new request.
2615 // FIXME: Current implementation doesn't support pre-downscale
2616 // mechanism for multiple sizes from same src, since we cache
2617 // pre-downscaled frame only for the latest requested scale.
2618 // The solution is to cache more than one scaled image frame
2619 // for each RasterImage.
2620 bool needScaleReq;
2621 if (mScaleResult.status == SCALE_DONE && mScaleResult.scale == scale) {
2622 // Grab and hold the surface to make sure the OS didn't destroy it
2623 mScaleResult.frame->GetSurface(getter_AddRefs(surf));
2624 needScaleReq = !surf;
2625 if (surf) {
2626 frame = mScaleResult.frame;
2627 userSpaceToImageSpace.Multiply(gfxMatrix().Scale(scale.width,
2628 scale.height));
2629
2630 // Since we're switching to a scaled image, we need to transform the
2631 // area of the subimage to draw accordingly, since imgFrame::Draw()
2632 // doesn't know about scaled frames.
2633 subimage.ScaleRoundOut(scale.width, scale.height);
2634 }
2635 } else {
2636 needScaleReq = !(mScaleResult.status == SCALE_PENDING &&
2637 mScaleResult.scale == scale);
2638 }
2639
2640 // If we're not waiting for exactly this result, and there's only one
2641 // instance of this image on this page, ask for a scale.
2642 if (needScaleReq && mLockCount == 1) {
2643 if (NS_FAILED(frame->LockImageData())) {
2644 frame->UnlockImageData();
2645 return false;
2646 }
2647
2648 // If we have an outstanding request, signal it to stop (if it can).
2649 if (mScaleRequest) {
2650 mScaleRequest->stopped = true;
2651 }
2652
2653 nsRefPtr<ScaleRunner> runner = new ScaleRunner(this, scale, frame);
2654 if (runner->IsOK()) {
2655 if (!sScaleWorkerThread) {
2656 NS_NewNamedThread("Image Scaler", getter_AddRefs(sScaleWorkerThread));
2657 ClearOnShutdown(&sScaleWorkerThread);
2658 }
2659
2660 sScaleWorkerThread->Dispatch(runner, NS_DISPATCH_NORMAL);
2661 }
2662 frame->UnlockImageData();
2663 }
2664 }
2665
2666 nsIntMargin padding(framerect.y,
2667 mSize.width - framerect.XMost(),
2668 mSize.height - framerect.YMost(),
2669 framerect.x);
2670
2671 return frame->Draw(aContext, aFilter, userSpaceToImageSpace,
2672 aFill, padding, subimage, aFlags);
2673 }
2674
2675 //******************************************************************************
2676 /* [noscript] void draw(in gfxContext aContext,
2677 * in gfxGraphicsFilter aFilter,
2678 * [const] in gfxMatrix aUserSpaceToImageSpace,
2679 * [const] in gfxRect aFill,
2680 * [const] in nsIntRect aSubimage,
2681 * [const] in nsIntSize aViewportSize,
2682 * [const] in SVGImageContext aSVGContext,
2683 * in uint32_t aWhichFrame,
2684 * in uint32_t aFlags); */
2685 NS_IMETHODIMP
2686 RasterImage::Draw(gfxContext *aContext,
2687 GraphicsFilter aFilter,
2688 const gfxMatrix &aUserSpaceToImageSpace,
2689 const gfxRect &aFill,
2690 const nsIntRect &aSubimage,
2691 const nsIntSize& /*aViewportSize - ignored*/,
2692 const SVGImageContext* /*aSVGContext - ignored*/,
2693 uint32_t aWhichFrame,
2694 uint32_t aFlags)
2695 {
2696 if (aWhichFrame > FRAME_MAX_VALUE)
2697 return NS_ERROR_INVALID_ARG;
2698
2699 if (mError)
2700 return NS_ERROR_FAILURE;
2701
2702 // Disallowed in the API
2703 if (mInDecoder && (aFlags & imgIContainer::FLAG_SYNC_DECODE))
2704 return NS_ERROR_FAILURE;
2705
2706 // Illegal -- you can't draw with non-default decode flags.
2707 // (Disabling colorspace conversion might make sense to allow, but
2708 // we don't currently.)
2709 if ((aFlags & DECODE_FLAGS_MASK) != DECODE_FLAGS_DEFAULT)
2710 return NS_ERROR_FAILURE;
2711
2712 NS_ENSURE_ARG_POINTER(aContext);
2713
2714 // We can only draw without discarding and redecoding in these cases:
2715 // * We have the default decode flags.
2716 // * We have exactly FLAG_DECODE_NO_PREMULTIPLY_ALPHA and the current frame
2717 // is opaque.
2718 bool haveDefaultFlags = (mFrameDecodeFlags == DECODE_FLAGS_DEFAULT);
2719 bool haveSafeAlphaFlags =
2720 (mFrameDecodeFlags == FLAG_DECODE_NO_PREMULTIPLY_ALPHA) &&
2721 FrameIsOpaque(FRAME_CURRENT);
2722
2723 if (!(haveDefaultFlags || haveSafeAlphaFlags)) {
2724 if (!CanForciblyDiscardAndRedecode())
2725 return NS_ERROR_NOT_AVAILABLE;
2726 ForceDiscard();
2727
2728 mFrameDecodeFlags = DECODE_FLAGS_DEFAULT;
2729 }
2730
2731 // If this image is a candidate for discarding, reset its position in the
2732 // discard tracker so we're less likely to discard it right away.
2733 //
2734 // (We don't normally draw unlocked images, so this conditition will usually
2735 // be false. But we will draw unlocked images if image locking is globally
2736 // disabled via the image.mem.allow_locking_in_content_processes pref.)
2737 if (DiscardingActive()) {
2738 DiscardTracker::Reset(&mDiscardTrackerNode);
2739 }
2740
2741
2742 if (IsUnlocked() && mStatusTracker) {
2743 mStatusTracker->OnUnlockedDraw();
2744 }
2745
2746 // We use !mDecoded && mHasSourceData to mean discarded.
2747 if (!mDecoded && mHasSourceData) {
2748 mDrawStartTime = TimeStamp::Now();
2749 }
2750
2751 // If a synchronous draw is requested, flush anything that might be sitting around
2752 if (aFlags & FLAG_SYNC_DECODE) {
2753 nsresult rv = SyncDecode();
2754 NS_ENSURE_SUCCESS(rv, rv);
2755 }
2756
2757 uint32_t frameIndex = aWhichFrame == FRAME_FIRST ? 0
2758 : GetCurrentImgFrameIndex();
2759 imgFrame* frame = GetDrawableImgFrame(frameIndex);
2760 if (!frame) {
2761 return NS_OK; // Getting the frame (above) touches the image and kicks off decoding
2762 }
2763
2764 bool drawn = DrawWithPreDownscaleIfNeeded(frame, aContext, aFilter,
2765 aUserSpaceToImageSpace, aFill,
2766 aSubimage, aFlags);
2767 if (!drawn) {
2768 // The OS threw out some or all of our buffer. Start decoding again.
2769 ForceDiscard();
2770 WantDecodedFrames();
2771 return NS_OK;
2772 }
2773
2774 if (mDecoded && !mDrawStartTime.IsNull()) {
2775 TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime;
2776 Telemetry::Accumulate(Telemetry::IMAGE_DECODE_ON_DRAW_LATENCY, int32_t(drawLatency.ToMicroseconds()));
2777 // clear the value of mDrawStartTime
2778 mDrawStartTime = TimeStamp();
2779 }
2780
2781 return NS_OK;
2782 }
2783
2784 //******************************************************************************
2785 /* void lockImage() */
2786 NS_IMETHODIMP
2787 RasterImage::LockImage()
2788 {
2789 MOZ_ASSERT(NS_IsMainThread(),
2790 "Main thread to encourage serialization with UnlockImage");
2791 if (mError)
2792 return NS_ERROR_FAILURE;
2793
2794 // Cancel the discard timer if it's there
2795 DiscardTracker::Remove(&mDiscardTrackerNode);
2796
2797 // Increment the lock count
2798 mLockCount++;
2799
2800 return NS_OK;
2801 }
2802
2803 //******************************************************************************
2804 /* void unlockImage() */
2805 NS_IMETHODIMP
2806 RasterImage::UnlockImage()
2807 {
2808 MOZ_ASSERT(NS_IsMainThread(),
2809 "Main thread to encourage serialization with LockImage");
2810 if (mError)
2811 return NS_ERROR_FAILURE;
2812
2813 // It's an error to call this function if the lock count is 0
2814 NS_ABORT_IF_FALSE(mLockCount > 0,
2815 "Calling UnlockImage with mLockCount == 0!");
2816 if (mLockCount == 0)
2817 return NS_ERROR_ABORT;
2818
2819 // We're locked, so discarding should not be active
2820 NS_ABORT_IF_FALSE(!DiscardingActive(), "Locked, but discarding activated");
2821
2822 // Decrement our lock count
2823 mLockCount--;
2824
2825 // If we've decoded this image once before, we're currently decoding again,
2826 // and our lock count is now zero (so nothing is forcing us to keep the
2827 // decoded data around), try to cancel the decode and throw away whatever
2828 // we've decoded.
2829 if (mHasBeenDecoded && mDecoder &&
2830 mLockCount == 0 && CanForciblyDiscard()) {
2831 PR_LOG(GetCompressedImageAccountingLog(), PR_LOG_DEBUG,
2832 ("RasterImage[0x%p] canceling decode because image "
2833 "is now unlocked.", this));
2834 ReentrantMonitorAutoEnter lock(mDecodingMonitor);
2835 FinishedSomeDecoding(eShutdownIntent_NotNeeded);
2836 ForceDiscard();
2837 return NS_OK;
2838 }
2839
2840 // Otherwise, we might still be a candidate for discarding in the future. If
2841 // we are, add ourselves to the discard tracker.
2842 if (CanDiscard()) {
2843 nsresult rv = DiscardTracker::Reset(&mDiscardTrackerNode);
2844 CONTAINER_ENSURE_SUCCESS(rv);
2845 }
2846
2847 return NS_OK;
2848 }
2849
2850 //******************************************************************************
2851 /* void requestDiscard() */
2852 NS_IMETHODIMP
2853 RasterImage::RequestDiscard()
2854 {
2855 if (CanDiscard() && CanForciblyDiscardAndRedecode()) {
2856 ForceDiscard();
2857 }
2858
2859 return NS_OK;
2860 }
2861
2862 // Flushes up to aMaxBytes to the decoder.
2863 nsresult
2864 RasterImage::DecodeSomeData(uint32_t aMaxBytes, DecodeStrategy aStrategy)
2865 {
2866 // We should have a decoder if we get here
2867 NS_ABORT_IF_FALSE(mDecoder, "trying to decode without decoder!");
2868
2869 mDecodingMonitor.AssertCurrentThreadIn();
2870
2871 // First, if we've just been called because we allocated a frame on the main
2872 // thread, let the decoder deal with the data it set aside at that time by
2873 // passing it a null buffer.
2874 if (mDecodeRequest->mAllocatedNewFrame) {
2875 mDecodeRequest->mAllocatedNewFrame = false;
2876 nsresult rv = WriteToDecoder(nullptr, 0, aStrategy);
2877 if (NS_FAILED(rv) || mDecoder->NeedsNewFrame()) {
2878 return rv;
2879 }
2880 }
2881
2882 // If we have nothing else to decode, return
2883 if (mBytesDecoded == mSourceData.Length())
2884 return NS_OK;
2885
2886 MOZ_ASSERT(mBytesDecoded < mSourceData.Length());
2887
2888 // write the proper amount of data
2889 uint32_t bytesToDecode = std::min(aMaxBytes,
2890 mSourceData.Length() - mBytesDecoded);
2891 nsresult rv = WriteToDecoder(mSourceData.Elements() + mBytesDecoded,
2892 bytesToDecode,
2893 aStrategy);
2894
2895 return rv;
2896 }
2897
2898 // There are various indicators that tell us we're finished with the decode
2899 // task at hand and can shut down the decoder.
2900 //
2901 // This method may not be called if there is no decoder.
2902 bool
2903 RasterImage::IsDecodeFinished()
2904 {
2905 // Precondition
2906 mDecodingMonitor.AssertCurrentThreadIn();
2907 NS_ABORT_IF_FALSE(mDecoder, "Can't call IsDecodeFinished() without decoder!");
2908
2909 // The decode is complete if we got what we wanted.
2910 if (mDecoder->IsSizeDecode()) {
2911 if (mDecoder->HasSize()) {
2912 return true;
2913 }
2914 } else if (mDecoder->GetDecodeDone()) {
2915 return true;
2916 }
2917
2918 // If the decoder returned because it needed a new frame and we haven't
2919 // written to it since then, the decoder may be storing data that it hasn't
2920 // decoded yet.
2921 if (mDecoder->NeedsNewFrame() ||
2922 (mDecodeRequest && mDecodeRequest->mAllocatedNewFrame)) {
2923 return false;
2924 }
2925
2926 // Otherwise, if we have all the source data and wrote all the source data,
2927 // we're done.
2928 //
2929 // (NB - This can be the case even for non-erroneous images because
2930 // Decoder::GetDecodeDone() might not return true until after we call
2931 // Decoder::Finish() in ShutdownDecoder())
2932 if (mHasSourceData && (mBytesDecoded == mSourceData.Length())) {
2933 return true;
2934 }
2935
2936 // If we get here, assume it's not finished.
2937 return false;
2938 }
2939
2940 // Indempotent error flagging routine. If a decoder is open, shuts it down.
2941 void
2942 RasterImage::DoError()
2943 {
2944 // If we've flagged an error before, we have nothing to do
2945 if (mError)
2946 return;
2947
2948 // We can't safely handle errors off-main-thread, so dispatch a worker to do it.
2949 if (!NS_IsMainThread()) {
2950 HandleErrorWorker::DispatchIfNeeded(this);
2951 return;
2952 }
2953
2954 // Calling FinishedSomeDecoding and CurrentStatusTracker requires us to be in
2955 // the decoding monitor.
2956 ReentrantMonitorAutoEnter lock(mDecodingMonitor);
2957
2958 // If we're mid-decode, shut down the decoder.
2959 if (mDecoder) {
2960 FinishedSomeDecoding(eShutdownIntent_Error);
2961 }
2962
2963 // Put the container in an error state.
2964 mError = true;
2965
2966 nsRefPtr<imgStatusTracker> statusTracker = CurrentStatusTracker();
2967 statusTracker->GetDecoderObserver()->OnError();
2968
2969 // Log our error
2970 LOG_CONTAINER_ERROR;
2971 }
2972
2973 /* static */ void
2974 RasterImage::HandleErrorWorker::DispatchIfNeeded(RasterImage* aImage)
2975 {
2976 if (!aImage->mPendingError) {
2977 aImage->mPendingError = true;
2978 nsRefPtr<HandleErrorWorker> worker = new HandleErrorWorker(aImage);
2979 NS_DispatchToMainThread(worker);
2980 }
2981 }
2982
2983 RasterImage::HandleErrorWorker::HandleErrorWorker(RasterImage* aImage)
2984 : mImage(aImage)
2985 {
2986 MOZ_ASSERT(mImage, "Should have image");
2987 }
2988
2989 NS_IMETHODIMP
2990 RasterImage::HandleErrorWorker::Run()
2991 {
2992 mImage->DoError();
2993
2994 return NS_OK;
2995 }
2996
2997 // nsIInputStream callback to copy the incoming image data directly to the
2998 // RasterImage without processing. The RasterImage is passed as the closure.
2999 // Always reads everything it gets, even if the data is erroneous.
3000 NS_METHOD
3001 RasterImage::WriteToRasterImage(nsIInputStream* /* unused */,
3002 void* aClosure,
3003 const char* aFromRawSegment,
3004 uint32_t /* unused */,
3005 uint32_t aCount,
3006 uint32_t* aWriteCount)
3007 {
3008 // Retrieve the RasterImage
3009 RasterImage* image = static_cast<RasterImage*>(aClosure);
3010
3011 // Copy the source data. Unless we hit OOM, we squelch the return value
3012 // here, because returning an error means that ReadSegments stops
3013 // reading data, violating our invariant that we read everything we get.
3014 // If we hit OOM then we fail and the load is aborted.
3015 nsresult rv = image->AddSourceData(aFromRawSegment, aCount);
3016 if (rv == NS_ERROR_OUT_OF_MEMORY) {
3017 image->DoError();
3018 return rv;
3019 }
3020
3021 // We wrote everything we got
3022 *aWriteCount = aCount;
3023
3024 return NS_OK;
3025 }
3026
3027 bool
3028 RasterImage::ShouldAnimate()
3029 {
3030 return ImageResource::ShouldAnimate() && GetNumFrames() >= 2 &&
3031 !mAnimationFinished;
3032 }
3033
3034 /* readonly attribute uint32_t framesNotified; */
3035 #ifdef DEBUG
3036 NS_IMETHODIMP
3037 RasterImage::GetFramesNotified(uint32_t *aFramesNotified)
3038 {
3039 NS_ENSURE_ARG_POINTER(aFramesNotified);
3040
3041 *aFramesNotified = mFramesNotified;
3042
3043 return NS_OK;
3044 }
3045 #endif
3046
3047 nsresult
3048 RasterImage::RequestDecodeIfNeeded(nsresult aStatus,
3049 eShutdownIntent aIntent,
3050 bool aDone,
3051 bool aWasSize)
3052 {
3053 MOZ_ASSERT(NS_IsMainThread());
3054
3055 // If we were a size decode and a full decode was requested, now's the time.
3056 if (NS_SUCCEEDED(aStatus) &&
3057 aIntent == eShutdownIntent_Done &&
3058 aDone &&
3059 aWasSize &&
3060 mWantFullDecode) {
3061 mWantFullDecode = false;
3062
3063 // If we're not meant to be storing source data and we just got the size,
3064 // we need to synchronously flush all the data we got to a full decoder.
3065 // When that decoder is shut down, we'll also clear our source data.
3066 return StoringSourceData() ? RequestDecode()
3067 : SyncDecode();
3068 }
3069
3070 // We don't need a full decode right now, so just return the existing status.
3071 return aStatus;
3072 }
3073
3074 nsresult
3075 RasterImage::FinishedSomeDecoding(eShutdownIntent aIntent /* = eShutdownIntent_Done */,
3076 DecodeRequest* aRequest /* = nullptr */)
3077 {
3078 MOZ_ASSERT(NS_IsMainThread());
3079
3080 mDecodingMonitor.AssertCurrentThreadIn();
3081
3082 nsRefPtr<DecodeRequest> request;
3083 if (aRequest) {
3084 request = aRequest;
3085 } else {
3086 request = mDecodeRequest;
3087 }
3088
3089 // Ensure that, if the decoder is the last reference to the image, we don't
3090 // destroy it by destroying the decoder.
3091 nsRefPtr<RasterImage> image(this);
3092
3093 bool done = false;
3094 bool wasSize = false;
3095 nsresult rv = NS_OK;
3096
3097 if (image->mDecoder) {
3098 image->mDecoder->MarkFrameDirty();
3099
3100 if (request && request->mChunkCount && !image->mDecoder->IsSizeDecode()) {
3101 Telemetry::Accumulate(Telemetry::IMAGE_DECODE_CHUNKS, request->mChunkCount);
3102 }
3103
3104 if (!image->mHasSize && image->mDecoder->HasSize()) {
3105 image->mDecoder->SetSizeOnImage();
3106 }
3107
3108 // If the decode finished, or we're specifically being told to shut down,
3109 // tell the image and shut down the decoder.
3110 if (image->IsDecodeFinished() || aIntent != eShutdownIntent_Done) {
3111 done = true;
3112
3113 // Hold on to a reference to the decoder until we're done with it
3114 nsRefPtr<Decoder> decoder = image->mDecoder;
3115
3116 wasSize = decoder->IsSizeDecode();
3117
3118 // Do some telemetry if this isn't a size decode.
3119 if (request && !wasSize) {
3120 Telemetry::Accumulate(Telemetry::IMAGE_DECODE_TIME,
3121 int32_t(request->mDecodeTime.ToMicroseconds()));
3122
3123 // We record the speed for only some decoders. The rest have
3124 // SpeedHistogram return HistogramCount.
3125 Telemetry::ID id = decoder->SpeedHistogram();
3126 if (id < Telemetry::HistogramCount) {
3127 int32_t KBps = int32_t(request->mImage->mBytesDecoded /
3128 (1024 * request->mDecodeTime.ToSeconds()));
3129 Telemetry::Accumulate(id, KBps);
3130 }
3131 }
3132
3133 // We need to shut down the decoder first, in order to ensure all
3134 // decoding routines have been finished.
3135 rv = image->ShutdownDecoder(aIntent);
3136 if (NS_FAILED(rv)) {
3137 image->DoError();
3138 }
3139 }
3140 }
3141
3142 ImageStatusDiff diff =
3143 request ? image->mStatusTracker->Difference(request->mStatusTracker)
3144 : image->mStatusTracker->DecodeStateAsDifference();
3145 image->mStatusTracker->ApplyDifference(diff);
3146
3147 if (mNotifying) {
3148 // Accumulate the status changes. We don't permit recursive notifications
3149 // because they cause subtle concurrency bugs, so we'll delay sending out
3150 // the notifications until we pop back to the lowest invocation of
3151 // FinishedSomeDecoding on the stack.
3152 NS_WARNING("Recursively notifying in RasterImage::FinishedSomeDecoding!");
3153 mStatusDiff.Combine(diff);
3154 } else {
3155 MOZ_ASSERT(mStatusDiff.IsNoChange(), "Shouldn't have an accumulated change at this point");
3156
3157 while (!diff.IsNoChange()) {
3158 // Tell the observers what happened.
3159 mNotifying = true;
3160 image->mStatusTracker->SyncNotifyDifference(diff);
3161 mNotifying = false;
3162
3163 // Gather any status changes that may have occurred as a result of sending
3164 // out the previous notifications. If there were any, we'll send out
3165 // notifications for them next.
3166 diff = mStatusDiff;
3167 mStatusDiff = ImageStatusDiff::NoChange();
3168 }
3169 }
3170
3171 return RequestDecodeIfNeeded(rv, aIntent, done, wasSize);
3172 }
3173
3174 NS_IMPL_ISUPPORTS(RasterImage::DecodePool,
3175 nsIObserver)
3176
3177 /* static */ RasterImage::DecodePool*
3178 RasterImage::DecodePool::Singleton()
3179 {
3180 if (!sSingleton) {
3181 MOZ_ASSERT(NS_IsMainThread());
3182 sSingleton = new DecodePool();
3183 ClearOnShutdown(&sSingleton);
3184 }
3185
3186 return sSingleton;
3187 }
3188
3189 already_AddRefed<nsIEventTarget>
3190 RasterImage::DecodePool::GetEventTarget()
3191 {
3192 nsCOMPtr<nsIEventTarget> target = do_QueryInterface(mThreadPool);
3193 return target.forget();
3194 }
3195
3196 #ifdef MOZ_NUWA_PROCESS
3197
3198 class RIDThreadPoolListener : public nsIThreadPoolListener
3199 {
3200 public:
3201 NS_DECL_THREADSAFE_ISUPPORTS
3202 NS_DECL_NSITHREADPOOLLISTENER
3203
3204 RIDThreadPoolListener() {}
3205 ~RIDThreadPoolListener() {}
3206 };
3207
3208 NS_IMPL_ISUPPORTS(RIDThreadPoolListener, nsIThreadPoolListener)
3209
3210 NS_IMETHODIMP
3211 RIDThreadPoolListener::OnThreadCreated()
3212 {
3213 if (IsNuwaProcess()) {
3214 NuwaMarkCurrentThread((void (*)(void *))nullptr, nullptr);
3215 }
3216 return NS_OK;
3217 }
3218
3219 NS_IMETHODIMP
3220 RIDThreadPoolListener::OnThreadShuttingDown()
3221 {
3222 return NS_OK;
3223 }
3224
3225 #endif // MOZ_NUWA_PROCESS
3226
3227 RasterImage::DecodePool::DecodePool()
3228 : mThreadPoolMutex("Thread Pool")
3229 {
3230 if (gMultithreadedDecoding) {
3231 mThreadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
3232 if (mThreadPool) {
3233 mThreadPool->SetName(NS_LITERAL_CSTRING("ImageDecoder"));
3234 uint32_t limit;
3235 if (gDecodingThreadLimit <= 0) {
3236 limit = std::max(PR_GetNumberOfProcessors(), 2) - 1;
3237 } else {
3238 limit = static_cast<uint32_t>(gDecodingThreadLimit);
3239 }
3240
3241 mThreadPool->SetThreadLimit(limit);
3242 mThreadPool->SetIdleThreadLimit(limit);
3243
3244 #ifdef MOZ_NUWA_PROCESS
3245 if (IsNuwaProcess()) {
3246 mThreadPool->SetListener(new RIDThreadPoolListener());
3247 }
3248 #endif
3249
3250 nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
3251 if (obsSvc) {
3252 obsSvc->AddObserver(this, "xpcom-shutdown-threads", false);
3253 }
3254 }
3255 }
3256 }
3257
3258 RasterImage::DecodePool::~DecodePool()
3259 {
3260 MOZ_ASSERT(NS_IsMainThread(), "Must shut down DecodePool on main thread!");
3261 }
3262
3263 NS_IMETHODIMP
3264 RasterImage::DecodePool::Observe(nsISupports *subject, const char *topic,
3265 const char16_t *data)
3266 {
3267 NS_ASSERTION(strcmp(topic, "xpcom-shutdown-threads") == 0, "oops");
3268
3269 nsCOMPtr<nsIThreadPool> threadPool;
3270
3271 {
3272 MutexAutoLock threadPoolLock(mThreadPoolMutex);
3273 threadPool = mThreadPool;
3274 mThreadPool = nullptr;
3275 }
3276
3277 if (threadPool) {
3278 threadPool->Shutdown();
3279 }
3280
3281 return NS_OK;
3282 }
3283
3284 void
3285 RasterImage::DecodePool::RequestDecode(RasterImage* aImg)
3286 {
3287 MOZ_ASSERT(aImg->mDecoder);
3288 aImg->mDecodingMonitor.AssertCurrentThreadIn();
3289
3290 // If we're currently waiting on a new frame for this image, we can't do any
3291 // decoding.
3292 if (!aImg->mDecoder->NeedsNewFrame()) {
3293 // No matter whether this is currently being decoded, we need to update the
3294 // number of bytes we want it to decode.
3295 aImg->mDecodeRequest->mBytesToDecode = aImg->mSourceData.Length() - aImg->mBytesDecoded;
3296
3297 if (aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_PENDING ||
3298 aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_ACTIVE) {
3299 // The image is already in our list of images to decode, or currently being
3300 // decoded, so we don't have to do anything else.
3301 return;
3302 }
3303
3304 aImg->mDecodeRequest->mRequestStatus = DecodeRequest::REQUEST_PENDING;
3305 nsRefPtr<DecodeJob> job = new DecodeJob(aImg->mDecodeRequest, aImg);
3306
3307 MutexAutoLock threadPoolLock(mThreadPoolMutex);
3308 if (!gMultithreadedDecoding || !mThreadPool) {
3309 NS_DispatchToMainThread(job);
3310 } else {
3311 mThreadPool->Dispatch(job, nsIEventTarget::DISPATCH_NORMAL);
3312 }
3313 }
3314 }
3315
3316 void
3317 RasterImage::DecodePool::DecodeABitOf(RasterImage* aImg, DecodeStrategy aStrategy)
3318 {
3319 MOZ_ASSERT(NS_IsMainThread());
3320 aImg->mDecodingMonitor.AssertCurrentThreadIn();
3321
3322 if (aImg->mDecodeRequest) {
3323 // If the image is waiting for decode work to be notified, go ahead and do that.
3324 if (aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_WORK_DONE) {
3325 aImg->FinishedSomeDecoding();
3326 }
3327 }
3328
3329 DecodeSomeOfImage(aImg, aStrategy);
3330
3331 aImg->FinishedSomeDecoding();
3332
3333 // If the decoder needs a new frame, enqueue an event to get it; that event
3334 // will enqueue another decode request when it's done.
3335 if (aImg->mDecoder && aImg->mDecoder->NeedsNewFrame()) {
3336 FrameNeededWorker::GetNewFrame(aImg);
3337 } else {
3338 // If we aren't yet finished decoding and we have more data in hand, add
3339 // this request to the back of the priority list.
3340 if (aImg->mDecoder &&
3341 !aImg->mError &&
3342 !aImg->IsDecodeFinished() &&
3343 aImg->mSourceData.Length() > aImg->mBytesDecoded) {
3344 RequestDecode(aImg);
3345 }
3346 }
3347 }
3348
3349 /* static */ void
3350 RasterImage::DecodePool::StopDecoding(RasterImage* aImg)
3351 {
3352 aImg->mDecodingMonitor.AssertCurrentThreadIn();
3353
3354 // If we haven't got a decode request, we're not currently decoding. (Having
3355 // a decode request doesn't imply we *are* decoding, though.)
3356 if (aImg->mDecodeRequest) {
3357 aImg->mDecodeRequest->mRequestStatus = DecodeRequest::REQUEST_STOPPED;
3358 }
3359 }
3360
3361 NS_IMETHODIMP
3362 RasterImage::DecodePool::DecodeJob::Run()
3363 {
3364 ReentrantMonitorAutoEnter lock(mImage->mDecodingMonitor);
3365
3366 // If we were interrupted, we shouldn't do any work.
3367 if (mRequest->mRequestStatus == DecodeRequest::REQUEST_STOPPED) {
3368 DecodeDoneWorker::NotifyFinishedSomeDecoding(mImage, mRequest);
3369 return NS_OK;
3370 }
3371
3372 // If someone came along and synchronously decoded us, there's nothing for us to do.
3373 if (!mImage->mDecoder || mImage->IsDecodeFinished()) {
3374 DecodeDoneWorker::NotifyFinishedSomeDecoding(mImage, mRequest);
3375 return NS_OK;
3376 }
3377
3378 // If we're a decode job that's been enqueued since a previous decode that
3379 // still needs a new frame, we can't do anything. Wait until the
3380 // FrameNeededWorker enqueues another frame.
3381 if (mImage->mDecoder->NeedsNewFrame()) {
3382 return NS_OK;
3383 }
3384
3385 mRequest->mRequestStatus = DecodeRequest::REQUEST_ACTIVE;
3386
3387 uint32_t oldByteCount = mImage->mBytesDecoded;
3388
3389 DecodeType type = DECODE_TYPE_UNTIL_DONE_BYTES;
3390
3391 // Multithreaded decoding can be disabled. If we've done so, we don't want to
3392 // monopolize the main thread, and will allow a timeout in DecodeSomeOfImage.
3393 if (NS_IsMainThread()) {
3394 type = DECODE_TYPE_UNTIL_TIME;
3395 }
3396
3397 DecodePool::Singleton()->DecodeSomeOfImage(mImage, DECODE_ASYNC, type, mRequest->mBytesToDecode);
3398
3399 uint32_t bytesDecoded = mImage->mBytesDecoded - oldByteCount;
3400
3401 mRequest->mRequestStatus = DecodeRequest::REQUEST_WORK_DONE;
3402
3403 // If the decoder needs a new frame, enqueue an event to get it; that event
3404 // will enqueue another decode request when it's done.
3405 if (mImage->mDecoder && mImage->mDecoder->NeedsNewFrame()) {
3406 FrameNeededWorker::GetNewFrame(mImage);
3407 }
3408 // If we aren't yet finished decoding and we have more data in hand, add
3409 // this request to the back of the list.
3410 else if (mImage->mDecoder &&
3411 !mImage->mError &&
3412 !mImage->mPendingError &&
3413 !mImage->IsDecodeFinished() &&
3414 bytesDecoded < mRequest->mBytesToDecode &&
3415 bytesDecoded > 0) {
3416 DecodePool::Singleton()->RequestDecode(mImage);
3417 } else {
3418 // Nothing more for us to do - let everyone know what happened.
3419 DecodeDoneWorker::NotifyFinishedSomeDecoding(mImage, mRequest);
3420 }
3421
3422 return NS_OK;
3423 }
3424
3425 RasterImage::DecodePool::DecodeJob::~DecodeJob()
3426 {
3427 if (gMultithreadedDecoding) {
3428 // Dispatch mImage to main thread to prevent mImage from being destructed by decode thread.
3429 nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
3430 NS_WARN_IF_FALSE(mainThread, "Couldn't get the main thread!");
3431 if (mainThread) {
3432 // Handle ambiguous nsISupports inheritance
3433 RasterImage* rawImg = nullptr;
3434 mImage.swap(rawImg);
3435 DebugOnly<nsresult> rv = NS_ProxyRelease(mainThread, NS_ISUPPORTS_CAST(ImageResource*, rawImg));
3436 MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to proxy release to main thread");
3437 }
3438 }
3439 }
3440
3441 nsresult
3442 RasterImage::DecodePool::DecodeUntilSizeAvailable(RasterImage* aImg)
3443 {
3444 MOZ_ASSERT(NS_IsMainThread());
3445 ReentrantMonitorAutoEnter lock(aImg->mDecodingMonitor);
3446
3447 if (aImg->mDecodeRequest) {
3448 // If the image is waiting for decode work to be notified, go ahead and do that.
3449 if (aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_WORK_DONE) {
3450 nsresult rv = aImg->FinishedSomeDecoding();
3451 if (NS_FAILED(rv)) {
3452 aImg->DoError();
3453 return rv;
3454 }
3455 }
3456 }
3457
3458 // We use DECODE_ASYNC here because we just want to get the size information
3459 // here and defer the rest of the work.
3460 nsresult rv = DecodeSomeOfImage(aImg, DECODE_ASYNC, DECODE_TYPE_UNTIL_SIZE);
3461 if (NS_FAILED(rv)) {
3462 return rv;
3463 }
3464
3465 // If the decoder needs a new frame, enqueue an event to get it; that event
3466 // will enqueue another decode request when it's done.
3467 if (aImg->mDecoder && aImg->mDecoder->NeedsNewFrame()) {
3468 FrameNeededWorker::GetNewFrame(aImg);
3469 } else {
3470 rv = aImg->FinishedSomeDecoding();
3471 }
3472
3473 return rv;
3474 }
3475
3476 nsresult
3477 RasterImage::DecodePool::DecodeSomeOfImage(RasterImage* aImg,
3478 DecodeStrategy aStrategy,
3479 DecodeType aDecodeType /* = DECODE_TYPE_UNTIL_TIME */,
3480 uint32_t bytesToDecode /* = 0 */)
3481 {
3482 NS_ABORT_IF_FALSE(aImg->mInitialized,
3483 "Worker active for uninitialized container!");
3484 aImg->mDecodingMonitor.AssertCurrentThreadIn();
3485
3486 // If an error is flagged, it probably happened while we were waiting
3487 // in the event queue.
3488 if (aImg->mError)
3489 return NS_OK;
3490
3491 // If there is an error worker pending (say because the main thread has enqueued
3492 // another decode request for us before processing the error worker) then bail out.
3493 if (aImg->mPendingError)
3494 return NS_OK;
3495
3496 // If mDecoded or we don't have a decoder, we must have finished already (for
3497 // example, a synchronous decode request came while the worker was pending).
3498 if (!aImg->mDecoder || aImg->mDecoded)
3499 return NS_OK;
3500
3501 // If we're doing synchronous decodes, and we're waiting on a new frame for
3502 // this image, get it now.
3503 if (aStrategy == DECODE_SYNC && aImg->mDecoder->NeedsNewFrame()) {
3504 MOZ_ASSERT(NS_IsMainThread());
3505
3506 aImg->mDecoder->AllocateFrame();
3507 aImg->mDecodeRequest->mAllocatedNewFrame = true;
3508 }
3509
3510 // If we're not synchronous, we can't allocate a frame right now.
3511 else if (aImg->mDecoder->NeedsNewFrame()) {
3512 return NS_OK;
3513 }
3514
3515 nsRefPtr<Decoder> decoderKungFuDeathGrip = aImg->mDecoder;
3516
3517 uint32_t maxBytes;
3518 if (aImg->mDecoder->IsSizeDecode()) {
3519 // Decode all available data if we're a size decode; they're cheap, and we
3520 // want them to be more or less synchronous.
3521 maxBytes = aImg->mSourceData.Length();
3522 } else {
3523 // We're only guaranteed to decode this many bytes, so in particular,
3524 // gDecodeBytesAtATime should be set high enough for us to read the size
3525 // from most images.
3526 maxBytes = gDecodeBytesAtATime;
3527 }
3528
3529 if (bytesToDecode == 0) {
3530 bytesToDecode = aImg->mSourceData.Length() - aImg->mBytesDecoded;
3531 }
3532
3533 int32_t chunkCount = 0;
3534 TimeStamp start = TimeStamp::Now();
3535 TimeStamp deadline = start + TimeDuration::FromMilliseconds(gMaxMSBeforeYield);
3536
3537 // We keep decoding chunks until:
3538 // * we don't have any data left to decode,
3539 // * the decode completes,
3540 // * we're an UNTIL_SIZE decode and we get the size, or
3541 // * we run out of time.
3542 // We also try to decode at least one "chunk" if we've allocated a new frame,
3543 // even if we have no more data to send to the decoder.
3544 while ((aImg->mSourceData.Length() > aImg->mBytesDecoded &&
3545 bytesToDecode > 0 &&
3546 !aImg->IsDecodeFinished() &&
3547 !(aDecodeType == DECODE_TYPE_UNTIL_SIZE && aImg->mHasSize) &&
3548 !aImg->mDecoder->NeedsNewFrame()) ||
3549 (aImg->mDecodeRequest && aImg->mDecodeRequest->mAllocatedNewFrame)) {
3550 chunkCount++;
3551 uint32_t chunkSize = std::min(bytesToDecode, maxBytes);
3552 nsresult rv = aImg->DecodeSomeData(chunkSize, aStrategy);
3553 if (NS_FAILED(rv)) {
3554 aImg->DoError();
3555 return rv;
3556 }
3557
3558 bytesToDecode -= chunkSize;
3559
3560 // Yield if we've been decoding for too long. We check this _after_ decoding
3561 // a chunk to ensure that we don't yield without doing any decoding.
3562 if (aDecodeType == DECODE_TYPE_UNTIL_TIME && TimeStamp::Now() >= deadline)
3563 break;
3564 }
3565
3566 if (aImg->mDecodeRequest) {
3567 aImg->mDecodeRequest->mDecodeTime += (TimeStamp::Now() - start);
3568 aImg->mDecodeRequest->mChunkCount += chunkCount;
3569 }
3570
3571 // Flush invalidations (and therefore paint) now that we've decoded all the
3572 // chunks we're going to.
3573 //
3574 // However, don't paint if:
3575 //
3576 // * This was an until-size decode. Until-size decodes are always followed
3577 // by normal decodes, so don't bother painting.
3578 //
3579 // * The decoder flagged an error. The decoder may have written garbage
3580 // into the output buffer; don't paint it to the screen.
3581 //
3582 // * We have all the source data. This disables progressive display of
3583 // previously-decoded images, thus letting us finish decoding faster,
3584 // since we don't waste time painting while we decode.
3585 // Decoder::PostFrameStop() will flush invalidations once the decode is
3586 // done.
3587
3588 if (aDecodeType != DECODE_TYPE_UNTIL_SIZE &&
3589 !aImg->mDecoder->HasError() &&
3590 !aImg->mHasSourceData) {
3591 aImg->mInDecoder = true;
3592 aImg->mDecoder->FlushInvalidations();
3593 aImg->mInDecoder = false;
3594 }
3595
3596 return NS_OK;
3597 }
3598
3599 RasterImage::DecodeDoneWorker::DecodeDoneWorker(RasterImage* image, DecodeRequest* request)
3600 : mImage(image)
3601 , mRequest(request)
3602 {}
3603
3604 void
3605 RasterImage::DecodeDoneWorker::NotifyFinishedSomeDecoding(RasterImage* image, DecodeRequest* request)
3606 {
3607 image->mDecodingMonitor.AssertCurrentThreadIn();
3608
3609 nsCOMPtr<nsIRunnable> worker = new DecodeDoneWorker(image, request);
3610 NS_DispatchToMainThread(worker);
3611 }
3612
3613 NS_IMETHODIMP
3614 RasterImage::DecodeDoneWorker::Run()
3615 {
3616 MOZ_ASSERT(NS_IsMainThread());
3617 ReentrantMonitorAutoEnter lock(mImage->mDecodingMonitor);
3618
3619 mImage->FinishedSomeDecoding(eShutdownIntent_Done, mRequest);
3620
3621 return NS_OK;
3622 }
3623
3624 RasterImage::FrameNeededWorker::FrameNeededWorker(RasterImage* image)
3625 : mImage(image)
3626 {}
3627
3628
3629 void
3630 RasterImage::FrameNeededWorker::GetNewFrame(RasterImage* image)
3631 {
3632 nsCOMPtr<nsIRunnable> worker = new FrameNeededWorker(image);
3633 NS_DispatchToMainThread(worker);
3634 }
3635
3636 NS_IMETHODIMP
3637 RasterImage::FrameNeededWorker::Run()
3638 {
3639 ReentrantMonitorAutoEnter lock(mImage->mDecodingMonitor);
3640 nsresult rv = NS_OK;
3641
3642 // If we got a synchronous decode in the mean time, we don't need to do
3643 // anything.
3644 if (mImage->mDecoder && mImage->mDecoder->NeedsNewFrame()) {
3645 rv = mImage->mDecoder->AllocateFrame();
3646 mImage->mDecodeRequest->mAllocatedNewFrame = true;
3647 }
3648
3649 if (NS_SUCCEEDED(rv) && mImage->mDecoder) {
3650 // By definition, we're not done decoding, so enqueue us for more decoding.
3651 DecodePool::Singleton()->RequestDecode(mImage);
3652 }
3653
3654 return NS_OK;
3655 }
3656
3657 } // namespace image
3658 } // namespace mozilla

mercurial