tor-browser

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

Image.h (14182B)


      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 #ifndef mozilla_image_Image_h
      7 #define mozilla_image_Image_h
      8 
      9 #include "mozilla/Attributes.h"
     10 #include "mozilla/MemoryReporting.h"
     11 #include "mozilla/ProfilerMarkers.h"
     12 #include "mozilla/SizeOfState.h"
     13 #include "mozilla/TimeStamp.h"
     14 
     15 #include "gfx2DGlue.h"
     16 #include "imgIContainer.h"
     17 #include "ImageContainer.h"
     18 #include "ImageRegion.h"
     19 #include "LookupResult.h"
     20 #include "nsStringFwd.h"
     21 #include "ProgressTracker.h"
     22 #include "SurfaceCache.h"
     23 #include "WebRenderImageProvider.h"
     24 
     25 class imgRequest;
     26 class nsIRequest;
     27 class nsIInputStream;
     28 
     29 namespace mozilla {
     30 namespace image {
     31 
     32 class Image;
     33 
     34 ///////////////////////////////////////////////////////////////////////////////
     35 // Memory Reporting
     36 ///////////////////////////////////////////////////////////////////////////////
     37 
     38 struct MemoryCounter {
     39  MemoryCounter()
     40      : mSource(0),
     41        mDecodedHeap(0),
     42        mDecodedNonHeap(0),
     43        mDecodedUnknown(0),
     44        mExternalHandles(0),
     45        mFrameIndex(0),
     46        mExternalId(0),
     47        mSurfaceTypes(0) {}
     48 
     49  void SetSource(size_t aCount) { mSource = aCount; }
     50  size_t Source() const { return mSource; }
     51  void SetDecodedHeap(size_t aCount) { mDecodedHeap = aCount; }
     52  size_t DecodedHeap() const { return mDecodedHeap; }
     53  void SetDecodedNonHeap(size_t aCount) { mDecodedNonHeap = aCount; }
     54  size_t DecodedNonHeap() const { return mDecodedNonHeap; }
     55  void SetDecodedUnknown(size_t aCount) { mDecodedUnknown = aCount; }
     56  size_t DecodedUnknown() const { return mDecodedUnknown; }
     57  void SetExternalHandles(size_t aCount) { mExternalHandles = aCount; }
     58  size_t ExternalHandles() const { return mExternalHandles; }
     59  void SetFrameIndex(size_t aIndex) { mFrameIndex = aIndex; }
     60  size_t FrameIndex() const { return mFrameIndex; }
     61  void SetExternalId(uint64_t aId) { mExternalId = aId; }
     62  uint64_t ExternalId() const { return mExternalId; }
     63  void SetSurfaceTypes(uint32_t aTypes) { mSurfaceTypes = aTypes; }
     64  uint32_t SurfaceTypes() const { return mSurfaceTypes; }
     65 
     66  MemoryCounter& operator+=(const MemoryCounter& aOther) {
     67    mSource += aOther.mSource;
     68    mDecodedHeap += aOther.mDecodedHeap;
     69    mDecodedNonHeap += aOther.mDecodedNonHeap;
     70    mDecodedUnknown += aOther.mDecodedUnknown;
     71    mExternalHandles += aOther.mExternalHandles;
     72    mSurfaceTypes |= aOther.mSurfaceTypes;
     73    return *this;
     74  }
     75 
     76 private:
     77  size_t mSource;
     78  size_t mDecodedHeap;
     79  size_t mDecodedNonHeap;
     80  size_t mDecodedUnknown;
     81  size_t mExternalHandles;
     82  size_t mFrameIndex;
     83  uint64_t mExternalId;
     84  uint32_t mSurfaceTypes;
     85 };
     86 
     87 enum class SurfaceMemoryCounterType { NORMAL, CONTAINER };
     88 
     89 struct SurfaceMemoryCounter {
     90  SurfaceMemoryCounter(
     91      const SurfaceKey& aKey, bool aIsLocked, bool aCannotSubstitute,
     92      bool aIsFactor2, bool aFinished,
     93      SurfaceMemoryCounterType aType = SurfaceMemoryCounterType::NORMAL)
     94      : mKey(aKey),
     95        mType(aType),
     96        mIsLocked(aIsLocked),
     97        mCannotSubstitute(aCannotSubstitute),
     98        mIsFactor2(aIsFactor2),
     99        mFinished(aFinished) {}
    100 
    101  const SurfaceKey& Key() const { return mKey; }
    102  MemoryCounter& Values() { return mValues; }
    103  const MemoryCounter& Values() const { return mValues; }
    104  SurfaceMemoryCounterType Type() const { return mType; }
    105  bool IsLocked() const { return mIsLocked; }
    106  bool CannotSubstitute() const { return mCannotSubstitute; }
    107  bool IsFactor2() const { return mIsFactor2; }
    108  bool IsFinished() const { return mFinished; }
    109 
    110 private:
    111  const SurfaceKey mKey;
    112  MemoryCounter mValues;
    113  const SurfaceMemoryCounterType mType;
    114  const bool mIsLocked;
    115  const bool mCannotSubstitute;
    116  const bool mIsFactor2;
    117  const bool mFinished;
    118 };
    119 
    120 struct ImageMemoryCounter {
    121  ImageMemoryCounter(imgRequest* aRequest, SizeOfState& aState, bool aIsUsed);
    122  ImageMemoryCounter(imgRequest* aRequest, Image* aImage, SizeOfState& aState,
    123                     bool aIsUsed);
    124 
    125  nsCString& URI() { return mURI; }
    126  const nsCString& URI() const { return mURI; }
    127  const nsTArray<SurfaceMemoryCounter>& Surfaces() const { return mSurfaces; }
    128  const gfx::IntSize IntrinsicSize() const { return mIntrinsicSize; }
    129  const MemoryCounter& Values() const { return mValues; }
    130  uint32_t Progress() const { return mProgress; }
    131  uint16_t Type() const { return mType; }
    132  bool IsUsed() const { return mIsUsed; }
    133  bool HasError() const { return mHasError; }
    134  bool IsValidating() const { return mValidating; }
    135 
    136  bool IsNotable() const {
    137    // Errors or requests without images are always notable.
    138    if (mHasError || mValidating || mProgress == UINT32_MAX ||
    139        mProgress & FLAG_HAS_ERROR || mType == imgIContainer::TYPE_REQUEST) {
    140      return true;
    141    }
    142 
    143    // Sufficiently large images are notable.
    144    const size_t NotableThreshold = 16 * 1024;
    145    size_t total = mValues.Source() + mValues.DecodedHeap() +
    146                   mValues.DecodedNonHeap() + mValues.DecodedUnknown();
    147    if (total >= NotableThreshold) {
    148      return true;
    149    }
    150 
    151    // Incomplete images are always notable as well; the odds of capturing
    152    // mid-decode should be fairly low.
    153    for (const auto& surface : mSurfaces) {
    154      if (!surface.IsFinished()) {
    155        return true;
    156      }
    157    }
    158 
    159    return false;
    160  }
    161 
    162 private:
    163  nsCString mURI;
    164  nsTArray<SurfaceMemoryCounter> mSurfaces;
    165  gfx::IntSize mIntrinsicSize;
    166  MemoryCounter mValues;
    167  uint32_t mProgress;
    168  uint16_t mType;
    169  const bool mIsUsed;
    170  bool mHasError;
    171  bool mValidating;
    172 };
    173 
    174 ///////////////////////////////////////////////////////////////////////////////
    175 // Image Base Types
    176 ///////////////////////////////////////////////////////////////////////////////
    177 
    178 class Image : public imgIContainer {
    179 public:
    180  /**
    181   * Flags for Image initialization.
    182   *
    183   * Meanings:
    184   *
    185   * INIT_FLAG_NONE: Lack of flags
    186   *
    187   * INIT_FLAG_DISCARDABLE: The container should be discardable
    188   *
    189   * INIT_FLAG_DECODE_IMMEDIATELY: The container should decode as soon as
    190   * possible, regardless of what our heuristics say.
    191   *
    192   * INIT_FLAG_TRANSIENT: The container is likely to exist for only a short time
    193   * before being destroyed. (For example, containers for
    194   * multipart/x-mixed-replace image parts fall into this category.) If this
    195   * flag is set, INIT_FLAG_DISCARDABLE and INIT_FLAG_DECODE_ONLY_ON_DRAW must
    196   * not be set.
    197   *
    198   * INIT_FLAG_SYNC_LOAD: The container is being loaded synchronously, so
    199   * it should avoid relying on async workers to get the container ready.
    200   */
    201  static const uint32_t INIT_FLAG_NONE = 0x0;
    202  static const uint32_t INIT_FLAG_DISCARDABLE = 0x1;
    203  static const uint32_t INIT_FLAG_DECODE_IMMEDIATELY = 0x2;
    204  static const uint32_t INIT_FLAG_TRANSIENT = 0x4;
    205  static const uint32_t INIT_FLAG_SYNC_LOAD = 0x8;
    206 
    207  virtual already_AddRefed<ProgressTracker> GetProgressTracker() = 0;
    208  virtual void SetProgressTracker(ProgressTracker* aProgressTracker) {}
    209 
    210  /**
    211   * The size, in bytes, occupied by the compressed source data of the image.
    212   * If MallocSizeOf does not work on this platform, uses a fallback approach to
    213   * ensure that something reasonable is always returned.
    214   */
    215  virtual size_t SizeOfSourceWithComputedFallback(
    216      SizeOfState& aState) const = 0;
    217 
    218  /**
    219   * Collect an accounting of the memory occupied by the image's surfaces (which
    220   * together make up its decoded data). Each surface is recorded as a separate
    221   * SurfaceMemoryCounter, stored in @aCounters.
    222   */
    223  virtual void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters,
    224                                     MallocSizeOf aMallocSizeOf) const = 0;
    225 
    226  virtual void IncrementAnimationConsumers() = 0;
    227  virtual void DecrementAnimationConsumers() = 0;
    228 #ifdef DEBUG
    229  virtual uint32_t GetAnimationConsumers() = 0;
    230 #endif
    231 
    232  /**
    233   * Called from OnDataAvailable when the stream associated with the image has
    234   * received new image data. The arguments are the same as OnDataAvailable's,
    235   * but by separating this functionality into a different method we don't
    236   * interfere with subclasses which wish to implement nsIStreamListener.
    237   *
    238   * Images should not do anything that could send out notifications until they
    239   * have received their first OnImageDataAvailable notification; in
    240   * particular, this means that instantiating decoders should be deferred
    241   * until OnImageDataAvailable is called.
    242   */
    243  virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
    244                                        nsIInputStream* aInStr,
    245                                        uint64_t aSourceOffset,
    246                                        uint32_t aCount) = 0;
    247 
    248  /**
    249   * Called from OnStopRequest when the image's underlying request completes.
    250   *
    251   * @param aRequest  The completed request.
    252   * @param aStatus   A success or failure code.
    253   * @param aLastPart Whether this is the final part of the underlying request.
    254   */
    255  virtual nsresult OnImageDataComplete(nsIRequest* aRequest, nsresult aStatus,
    256                                       bool aLastPart) = 0;
    257 
    258  /**
    259   * Called when the SurfaceCache discards a surface belonging to this image.
    260   */
    261  virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) = 0;
    262 
    263  virtual void SetInnerWindowID(uint64_t aInnerWindowId) = 0;
    264  virtual uint64_t InnerWindowID() const = 0;
    265 
    266  virtual bool HasError() = 0;
    267  virtual void SetHasError() = 0;
    268 
    269  virtual nsIURI* GetURI() const = 0;
    270 
    271  NS_IMETHOD GetHotspotX(int32_t* aX) override {
    272    *aX = 0;
    273    return NS_OK;
    274  }
    275  NS_IMETHOD GetHotspotY(int32_t* aY) override {
    276    *aY = 0;
    277    return NS_OK;
    278  }
    279 };
    280 
    281 class ImageResource : public Image {
    282 public:
    283  already_AddRefed<ProgressTracker> GetProgressTracker() override {
    284    RefPtr<ProgressTracker> progressTracker = mProgressTracker;
    285    MOZ_ASSERT(progressTracker);
    286    return progressTracker.forget();
    287  }
    288 
    289  void SetProgressTracker(ProgressTracker* aProgressTracker) final {
    290    MOZ_ASSERT(aProgressTracker);
    291    MOZ_ASSERT(!mProgressTracker);
    292    mProgressTracker = aProgressTracker;
    293  }
    294 
    295  virtual void IncrementAnimationConsumers() override;
    296  virtual void DecrementAnimationConsumers() override;
    297 #ifdef DEBUG
    298  virtual uint32_t GetAnimationConsumers() override {
    299    return mAnimationConsumers;
    300  }
    301 #endif
    302 
    303  virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) override {}
    304 
    305  virtual void SetInnerWindowID(uint64_t aInnerWindowId) override {
    306    mInnerWindowId = aInnerWindowId;
    307  }
    308  virtual uint64_t InnerWindowID() const override { return mInnerWindowId; }
    309 
    310  virtual bool HasError() override { return mError; }
    311  virtual void SetHasError() override { mError = true; }
    312 
    313  /*
    314   * Returns a non-AddRefed pointer to the URI associated with this image.
    315   * Illegal to use off-main-thread.
    316   */
    317  nsIURI* GetURI() const override { return mURI; }
    318 
    319  /*
    320   * Should be called by its subclasses after they populate @aCounters so that
    321   * we can cross reference against any of our ImageContainers that contain
    322   * surfaces not in the cache.
    323   */
    324  void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters,
    325                             MallocSizeOf aMallocSizeOf) const override;
    326 
    327  ImageProviderId GetImageProviderId() const { return mProviderId; }
    328 
    329 protected:
    330  explicit ImageResource(nsIURI* aURI);
    331  ~ImageResource();
    332 
    333  bool GetSpecTruncatedTo1k(nsCString& aSpec) const;
    334 
    335  // Shared functionality for implementors of imgIContainer. Every
    336  // implementation of attribute animationMode should forward here.
    337  nsresult GetAnimationModeInternal(uint16_t* aAnimationMode);
    338  nsresult SetAnimationModeInternal(uint16_t aAnimationMode);
    339 
    340  /**
    341   * Helper for RequestRefresh.
    342   *
    343   * If we've had a "recent" refresh (i.e. if this image is being used in
    344   * multiple documents & some other document *just* called RequestRefresh() on
    345   * this image with a timestamp close to aTime), this method returns true.
    346   *
    347   * Otherwise, this method updates mLastRefreshTime to aTime & returns false.
    348   */
    349  bool HadRecentRefresh(const TimeStamp& aTime);
    350 
    351  /**
    352   * Decides whether animation should or should not be happening,
    353   * and makes sure the right thing is being done.
    354   */
    355  virtual void EvaluateAnimation();
    356 
    357  /**
    358   * Extended by child classes, if they have additional
    359   * conditions for being able to animate.
    360   */
    361  virtual bool ShouldAnimate() {
    362    return mAnimationConsumers > 0 && mAnimationMode != kDontAnimMode;
    363  }
    364 
    365  virtual nsresult StartAnimation() = 0;
    366  virtual nsresult StopAnimation() = 0;
    367 
    368  void SendOnUnlockedDraw(uint32_t aFlags);
    369 
    370 #ifdef DEBUG
    371  // Records the image drawing for startup performance testing.
    372  void NotifyDrawingObservers();
    373 #endif
    374 
    375  // Member data shared by all implementations of this abstract class
    376  RefPtr<ProgressTracker> mProgressTracker;
    377  nsCOMPtr<nsIURI> mURI;
    378  TimeStamp mLastRefreshTime;
    379  uint64_t mInnerWindowId;
    380  uint32_t mAnimationConsumers;
    381  uint16_t mAnimationMode;  // Enum values in imgIContainer
    382  bool mInitialized : 1;    // Have we been initialized?
    383  bool mAnimating : 1;      // Are we currently animating?
    384  bool mError : 1;          // Error handling
    385 
    386  class MOZ_RAII AutoProfilerImagePaintMarker {
    387   public:
    388    explicit AutoProfilerImagePaintMarker(ImageResource* self) {
    389      if (self->mURI && profiler_thread_is_being_profiled_for_markers()) {
    390        mStartTime = TimeStamp::Now();
    391        static const size_t sMaxTruncatedLength = 1024;
    392        mSpec = nsContentUtils::TruncatedURLForDisplay(self->mURI,
    393                                                       sMaxTruncatedLength);
    394      }
    395    }
    396 
    397    ~AutoProfilerImagePaintMarker() {
    398      if (!mSpec.IsEmpty()) {
    399        PROFILER_MARKER_TEXT("Image Paint", GRAPHICS,
    400                             MarkerTiming::IntervalUntilNowFrom(mStartTime),
    401                             mSpec);
    402      }
    403    }
    404 
    405   protected:
    406    TimeStamp mStartTime;
    407    nsAutoCString mSpec;
    408  };
    409 
    410 private:
    411  ImageProviderId mProviderId;
    412 };
    413 
    414 }  // namespace image
    415 }  // namespace mozilla
    416 
    417 #endif  // mozilla_image_Image_h