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