tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Image.cpp (8012B)


      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 #include "Image.h"
      7 
      8 #include "imgRequest.h"
      9 #include "WebRenderImageProvider.h"
     10 #include "nsIObserverService.h"
     11 #include "nsRefreshDriver.h"
     12 #include "nsContentUtils.h"
     13 #include "mozilla/Atomics.h"
     14 #include "mozilla/gfx/Point.h"
     15 #include "mozilla/gfx/Rect.h"
     16 #include "mozilla/gfx/SourceSurfaceRawData.h"
     17 #include "mozilla/Services.h"
     18 #include "mozilla/SizeOfState.h"
     19 #include "mozilla/TimeStamp.h"
     20 // for Tie
     21 #include "mozilla/layers/SharedSurfacesChild.h"
     22 
     23 namespace mozilla {
     24 namespace image {
     25 
     26 WebRenderImageProvider::WebRenderImageProvider(const ImageResource* aImage)
     27    : mProviderId(aImage->GetImageProviderId()) {}
     28 
     29 /* static */ ImageProviderId WebRenderImageProvider::AllocateProviderId() {
     30  // Callable on all threads.
     31  static Atomic<ImageProviderId> sProviderId(0u);
     32  return ++sProviderId;
     33 }
     34 
     35 ///////////////////////////////////////////////////////////////////////////////
     36 // Memory Reporting
     37 ///////////////////////////////////////////////////////////////////////////////
     38 
     39 ImageMemoryCounter::ImageMemoryCounter(imgRequest* aRequest,
     40                                       SizeOfState& aState, bool aIsUsed)
     41    : mProgress(UINT32_MAX),
     42      mType(UINT16_MAX),
     43      mIsUsed(aIsUsed),
     44      mHasError(false),
     45      mValidating(false) {
     46  MOZ_ASSERT(aRequest);
     47 
     48  // We don't have the image object yet, but we can get some information.
     49  nsCOMPtr<nsIURI> imageURL;
     50  nsresult rv = aRequest->GetURI(getter_AddRefs(imageURL));
     51  if (NS_SUCCEEDED(rv) && imageURL) {
     52    imageURL->GetSpec(mURI);
     53  }
     54 
     55  mType = imgIContainer::TYPE_REQUEST;
     56  mHasError = NS_FAILED(aRequest->GetImageErrorCode());
     57  mValidating = !!aRequest->GetValidator();
     58 
     59  RefPtr<ProgressTracker> tracker = aRequest->GetProgressTracker();
     60  if (tracker) {
     61    mProgress = tracker->GetProgress();
     62  }
     63 }
     64 
     65 ImageMemoryCounter::ImageMemoryCounter(imgRequest* aRequest, Image* aImage,
     66                                       SizeOfState& aState, bool aIsUsed)
     67    : mProgress(UINT32_MAX),
     68      mType(UINT16_MAX),
     69      mIsUsed(aIsUsed),
     70      mHasError(false),
     71      mValidating(false) {
     72  MOZ_ASSERT(aRequest);
     73  MOZ_ASSERT(aImage);
     74 
     75  // Extract metadata about the image.
     76  nsCOMPtr<nsIURI> imageURL(aImage->GetURI());
     77  if (imageURL) {
     78    imageURL->GetSpec(mURI);
     79  }
     80 
     81  ImageIntrinsicSize size;
     82  if (NS_SUCCEEDED(aImage->GetIntrinsicSize(&size))) {
     83    mIntrinsicSize.SizeTo(size.mWidth.valueOr(0), size.mHeight.valueOr(0));
     84  }  // else, leave mIntrinsicSize default-initialized as IntSize(0,0).
     85 
     86  mType = aImage->GetType();
     87  mHasError = aImage->HasError();
     88  mValidating = !!aRequest->GetValidator();
     89 
     90  RefPtr<ProgressTracker> tracker = aImage->GetProgressTracker();
     91  if (tracker) {
     92    mProgress = tracker->GetProgress();
     93  }
     94 
     95  // Populate memory counters for source and decoded data.
     96  mValues.SetSource(aImage->SizeOfSourceWithComputedFallback(aState));
     97  aImage->CollectSizeOfSurfaces(mSurfaces, aState.mMallocSizeOf);
     98 
     99  // Compute totals.
    100  for (const SurfaceMemoryCounter& surfaceCounter : mSurfaces) {
    101    mValues += surfaceCounter.Values();
    102  }
    103 }
    104 
    105 ///////////////////////////////////////////////////////////////////////////////
    106 // Image Base Types
    107 ///////////////////////////////////////////////////////////////////////////////
    108 
    109 bool ImageResource::GetSpecTruncatedTo1k(nsCString& aSpec) const {
    110  static const size_t sMaxTruncatedLength = 1024;
    111 
    112  mURI->GetSpec(aSpec);
    113  if (sMaxTruncatedLength >= aSpec.Length()) {
    114    return true;
    115  }
    116 
    117  aSpec.Truncate(sMaxTruncatedLength);
    118  return false;
    119 }
    120 
    121 void ImageResource::CollectSizeOfSurfaces(
    122    nsTArray<SurfaceMemoryCounter>& aCounters,
    123    MallocSizeOf aMallocSizeOf) const {
    124  SurfaceCache::CollectSizeOfSurfaces(ImageKey(this), aCounters, aMallocSizeOf);
    125 }
    126 
    127 // Constructor
    128 ImageResource::ImageResource(nsIURI* aURI)
    129    : mURI(aURI),
    130      mInnerWindowId(0),
    131      mAnimationConsumers(0),
    132      mAnimationMode(kNormalAnimMode),
    133      mInitialized(false),
    134      mAnimating(false),
    135      mError(false),
    136      mProviderId(WebRenderImageProvider::AllocateProviderId()) {}
    137 
    138 ImageResource::~ImageResource() {
    139  // Ask our ProgressTracker to drop its weak reference to us.
    140  mProgressTracker->ResetImage();
    141 }
    142 
    143 void ImageResource::IncrementAnimationConsumers() {
    144  MOZ_ASSERT(NS_IsMainThread(),
    145             "Main thread only to encourage serialization "
    146             "with DecrementAnimationConsumers");
    147  mAnimationConsumers++;
    148 }
    149 
    150 void ImageResource::DecrementAnimationConsumers() {
    151  MOZ_ASSERT(NS_IsMainThread(),
    152             "Main thread only to encourage serialization "
    153             "with IncrementAnimationConsumers");
    154  MOZ_ASSERT(mAnimationConsumers >= 1, "Invalid no. of animation consumers!");
    155  mAnimationConsumers--;
    156 }
    157 
    158 nsresult ImageResource::GetAnimationModeInternal(uint16_t* aAnimationMode) {
    159  if (mError) {
    160    return NS_ERROR_FAILURE;
    161  }
    162 
    163  NS_ENSURE_ARG_POINTER(aAnimationMode);
    164 
    165  *aAnimationMode = mAnimationMode;
    166  return NS_OK;
    167 }
    168 
    169 nsresult ImageResource::SetAnimationModeInternal(uint16_t aAnimationMode) {
    170  if (mError) {
    171    return NS_ERROR_FAILURE;
    172  }
    173 
    174  NS_ASSERTION(aAnimationMode == kNormalAnimMode ||
    175                   aAnimationMode == kDontAnimMode ||
    176                   aAnimationMode == kLoopOnceAnimMode,
    177               "Wrong Animation Mode is being set!");
    178 
    179  mAnimationMode = aAnimationMode;
    180 
    181  return NS_OK;
    182 }
    183 
    184 bool ImageResource::HadRecentRefresh(const TimeStamp& aTime) {
    185  // Our threshold for "recent" is 1/2 of the default refresh-driver interval.
    186  // This ensures that we allow for frame rates at least as fast as the
    187  // refresh driver's default rate.
    188  static TimeDuration recentThreshold =
    189      TimeDuration::FromMilliseconds(nsRefreshDriver::DefaultInterval() / 2.0);
    190 
    191  if (!mLastRefreshTime.IsNull() &&
    192      aTime - mLastRefreshTime < recentThreshold) {
    193    return true;
    194  }
    195 
    196  // else, we can proceed with a refresh.
    197  // But first, update our last refresh time:
    198  mLastRefreshTime = aTime;
    199  return false;
    200 }
    201 
    202 void ImageResource::EvaluateAnimation() {
    203  if (!mAnimating && ShouldAnimate()) {
    204    nsresult rv = StartAnimation();
    205    mAnimating = NS_SUCCEEDED(rv);
    206  } else if (mAnimating && !ShouldAnimate()) {
    207    StopAnimation();
    208  }
    209 }
    210 
    211 void ImageResource::SendOnUnlockedDraw(uint32_t aFlags) {
    212  if (!mProgressTracker) {
    213    return;
    214  }
    215 
    216  if (!(aFlags & FLAG_ASYNC_NOTIFY)) {
    217    mProgressTracker->OnUnlockedDraw();
    218  } else {
    219    NotNull<RefPtr<ImageResource>> image = WrapNotNull(this);
    220    nsCOMPtr<nsIEventTarget> eventTarget = GetMainThreadSerialEventTarget();
    221    nsCOMPtr<nsIRunnable> ev = NS_NewRunnableFunction(
    222        "image::ImageResource::SendOnUnlockedDraw", [=]() -> void {
    223          RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
    224          if (tracker) {
    225            tracker->OnUnlockedDraw();
    226          }
    227        });
    228    eventTarget->Dispatch(CreateRenderBlockingRunnable(ev.forget()),
    229                          NS_DISPATCH_NORMAL);
    230  }
    231 }
    232 
    233 #ifdef DEBUG
    234 void ImageResource::NotifyDrawingObservers() {
    235  if (!mURI || !NS_IsMainThread()) {
    236    return;
    237  }
    238 
    239  if (!mURI->SchemeIs("resource") && !mURI->SchemeIs("chrome")) {
    240    return;
    241  }
    242 
    243  // Record the image drawing for startup performance testing.
    244  nsCOMPtr<nsIURI> uri = mURI;
    245  nsContentUtils::AddScriptRunner(NS_NewRunnableFunction(
    246      "image::ImageResource::NotifyDrawingObservers", [uri]() {
    247        nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
    248        NS_WARNING_ASSERTION(obs, "Can't get an observer service handle");
    249        if (obs) {
    250          nsAutoCString spec;
    251          uri->GetSpec(spec);
    252          obs->NotifyObservers(nullptr, "image-drawing",
    253                               NS_ConvertUTF8toUTF16(spec).get());
    254        }
    255      }));
    256 }
    257 #endif
    258 
    259 }  // namespace image
    260 }  // namespace mozilla