tor-browser

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

imgFrame.h (14457B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 *
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_image_imgFrame_h
      8 #define mozilla_image_imgFrame_h
      9 
     10 #include <functional>
     11 #include <utility>
     12 
     13 #include "AnimationParams.h"
     14 #include "MainThreadUtils.h"
     15 #include "gfxDrawable.h"
     16 #include "mozilla/layers/SourceSurfaceSharedData.h"
     17 #include "mozilla/Maybe.h"
     18 #include "mozilla/MemoryReporting.h"
     19 #include "mozilla/Monitor.h"
     20 #include "nsRect.h"
     21 
     22 namespace mozilla {
     23 namespace image {
     24 
     25 class ImageRegion;
     26 class DrawableFrameRef;
     27 class RawAccessFrameRef;
     28 
     29 enum class Opacity : uint8_t { FULLY_OPAQUE, SOME_TRANSPARENCY };
     30 
     31 class imgFrame {
     32  typedef gfx::SourceSurfaceSharedData SourceSurfaceSharedData;
     33  typedef gfx::DrawTarget DrawTarget;
     34  typedef gfx::SamplingFilter SamplingFilter;
     35  typedef gfx::IntPoint IntPoint;
     36  typedef gfx::IntRect IntRect;
     37  typedef gfx::IntSize IntSize;
     38  typedef gfx::SourceSurface SourceSurface;
     39  typedef gfx::SurfaceFormat SurfaceFormat;
     40 
     41 public:
     42  MOZ_DECLARE_REFCOUNTED_TYPENAME(imgFrame)
     43  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(imgFrame)
     44 
     45  imgFrame();
     46 
     47  /**
     48   * Initialize this imgFrame with an empty surface and prepare it for being
     49   * written to by a decoder.
     50   *
     51   * This is appropriate for use with decoded images, but it should not be used
     52   * when drawing content into an imgFrame, as it may use a different graphics
     53   * backend than normal content drawing.
     54   */
     55  nsresult InitForDecoder(const nsIntSize& aImageSize, SurfaceFormat aFormat,
     56                          bool aNonPremult,
     57                          const Maybe<AnimationParams>& aAnimParams,
     58                          bool aShouldRecycle,
     59                          uint32_t* aImageDataLength = nullptr);
     60 
     61  /**
     62   * Reinitialize this imgFrame with the new parameters, but otherwise retain
     63   * the underlying buffer.
     64   *
     65   * This is appropriate for use with animated images, where the decoder was
     66   * given an IDecoderFrameRecycler object which may yield a recycled imgFrame
     67   * that was discarded to save memory.
     68   */
     69  nsresult InitForDecoderRecycle(const AnimationParams& aAnimParams,
     70                                 uint32_t* aImageDataLength = nullptr);
     71 
     72  /**
     73   * Initialize this imgFrame with a new surface and draw the provided
     74   * gfxDrawable into it.
     75   *
     76   * This is appropriate to use when drawing content into an imgFrame, as it
     77   * uses the same graphics backend as normal content drawing. The downside is
     78   * that the underlying surface may not be stored in a volatile buffer on all
     79   * platforms, and raw access to the surface (using RawAccessRef()) may be much
     80   * more expensive than in the InitForDecoder() case.
     81   *
     82   * aBackend specifies the DrawTarget backend type this imgFrame is supposed
     83   *          to be drawn to.
     84   */
     85  nsresult InitWithDrawable(gfxDrawable* aDrawable, const nsIntSize& aSize,
     86                            const SurfaceFormat aFormat,
     87                            SamplingFilter aSamplingFilter,
     88                            uint32_t aImageFlags, gfx::BackendType aBackend);
     89 
     90  DrawableFrameRef DrawableRef();
     91 
     92  /**
     93   * Create a RawAccessFrameRef for the frame.
     94   */
     95  RawAccessFrameRef RawAccessRef(
     96      gfx::DataSourceSurface::MapType aMapType = gfx::DataSourceSurface::READ);
     97 
     98  bool Draw(gfxContext* aContext, const ImageRegion& aRegion,
     99            SamplingFilter aSamplingFilter, uint32_t aImageFlags,
    100            float aOpacity);
    101 
    102  nsresult ImageUpdated(const nsIntRect& aUpdateRect);
    103 
    104  /**
    105   * Mark this imgFrame as completely decoded, and set final options.
    106   *
    107   * You must always call either Finish() or Abort() before releasing the last
    108   * RawAccessFrameRef pointing to an imgFrame.
    109   *
    110   * @param aFrameOpacity    Whether this imgFrame is opaque.
    111   * @param aFinalize        Finalize the underlying surface (e.g. so that it
    112   *                         may be marked as read only if possible).
    113   */
    114  void Finish(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
    115              bool aFinalize = true,
    116              bool aOrientationSwapsWidthAndHeight = false);
    117 
    118  /**
    119   * Mark this imgFrame as aborted. This informs the imgFrame that if it isn't
    120   * completely decoded now, it never will be.
    121   *
    122   * You must always call either Finish() or Abort() before releasing the last
    123   * RawAccessFrameRef pointing to an imgFrame.
    124   */
    125  void Abort();
    126 
    127  /**
    128   * Returns true if this imgFrame has been aborted.
    129   */
    130  bool IsAborted() const;
    131 
    132  /**
    133   * Returns true if this imgFrame is completely decoded.
    134   */
    135  bool IsFinished() const;
    136 
    137  /**
    138   * Blocks until this imgFrame is either completely decoded, or is marked as
    139   * aborted.
    140   *
    141   * Note that calling this on the main thread _blocks the main thread_. Be very
    142   * careful in your use of this method to avoid excessive main thread jank or
    143   * deadlock.
    144   */
    145  void WaitUntilFinished() const;
    146 
    147  /**
    148   * Returns the number of bytes per pixel this imgFrame requires.
    149   */
    150  uint32_t GetBytesPerPixel() const { return 4; }
    151 
    152  const IntSize& GetSize() const { return mImageSize; }
    153  IntRect GetRect() const { return IntRect(IntPoint(0, 0), mImageSize); }
    154  const IntRect& GetBlendRect() const { return mBlendRect; }
    155  IntRect GetBoundedBlendRect() const {
    156    return mBlendRect.Intersect(GetRect());
    157  }
    158  nsIntRect GetDecodedRect() const {
    159    MonitorAutoLock lock(mMonitor);
    160    return mDecoded;
    161  }
    162  FrameTimeout GetTimeout() const { return mTimeout; }
    163  BlendMethod GetBlendMethod() const { return mBlendMethod; }
    164  DisposalMethod GetDisposalMethod() const { return mDisposalMethod; }
    165  bool FormatHasAlpha() const { return mFormat == SurfaceFormat::OS_RGBA; }
    166 
    167  const IntRect& GetDirtyRect() const { return mDirtyRect; }
    168  void SetDirtyRect(const IntRect& aDirtyRect) { mDirtyRect = aDirtyRect; }
    169 
    170  void FinalizeSurface();
    171  already_AddRefed<SourceSurface> GetSourceSurface();
    172 
    173  struct AddSizeOfCbData : public SourceSurface::SizeOfInfo {
    174    AddSizeOfCbData() : mIndex(0), mFinished(false) {}
    175 
    176    size_t mIndex;
    177    bool mFinished;
    178  };
    179 
    180  typedef std::function<void(AddSizeOfCbData& aMetadata)> AddSizeOfCb;
    181 
    182  void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
    183                              const AddSizeOfCb& aCallback) const;
    184 
    185 private:  // methods
    186  ~imgFrame();
    187 
    188  bool AreAllPixelsWritten() const MOZ_REQUIRES(mMonitor);
    189  nsresult ImageUpdatedInternal(const nsIntRect& aUpdateRect);
    190  uint32_t GetImageBytesPerRow() const;
    191  uint32_t GetImageDataLength() const;
    192  void FinalizeSurfaceInternal();
    193  already_AddRefed<SourceSurface> GetSourceSurfaceInternal();
    194 
    195  struct SurfaceWithFormat {
    196    RefPtr<gfxDrawable> mDrawable;
    197    SurfaceFormat mFormat;
    198    SurfaceWithFormat() : mFormat(SurfaceFormat::UNKNOWN) {}
    199    SurfaceWithFormat(gfxDrawable* aDrawable, SurfaceFormat aFormat)
    200        : mDrawable(aDrawable), mFormat(aFormat) {}
    201    SurfaceWithFormat(SurfaceWithFormat&& aOther)
    202        : mDrawable(std::move(aOther.mDrawable)), mFormat(aOther.mFormat) {}
    203    SurfaceWithFormat& operator=(SurfaceWithFormat&& aOther) {
    204      mDrawable = std::move(aOther.mDrawable);
    205      mFormat = aOther.mFormat;
    206      return *this;
    207    }
    208    SurfaceWithFormat& operator=(const SurfaceWithFormat& aOther) = delete;
    209    SurfaceWithFormat(const SurfaceWithFormat& aOther) = delete;
    210    bool IsValid() { return !!mDrawable; }
    211  };
    212 
    213  SurfaceWithFormat SurfaceForDrawing(bool aDoPartialDecode, bool aDoTile,
    214                                      ImageRegion& aRegion,
    215                                      SourceSurface* aSurface);
    216 
    217 private:  // data
    218  friend class DrawableFrameRef;
    219  friend class RawAccessFrameRef;
    220  friend class UnlockImageDataRunnable;
    221 
    222  //////////////////////////////////////////////////////////////////////////////
    223  // Thread-safe mutable data, protected by mMonitor.
    224  //////////////////////////////////////////////////////////////////////////////
    225 
    226  mutable Monitor mMonitor;
    227 
    228  /**
    229   * Used for rasterized images, this contains the raw pixel data.
    230   */
    231  RefPtr<SourceSurfaceSharedData> mRawSurface MOZ_GUARDED_BY(mMonitor);
    232  RefPtr<SourceSurfaceSharedData> mBlankRawSurface MOZ_GUARDED_BY(mMonitor);
    233 
    234  /**
    235   * Used for vector images that were not rasterized directly. This might be a
    236   * blob recording or native surface.
    237   */
    238  RefPtr<SourceSurface> mOptSurface MOZ_GUARDED_BY(mMonitor);
    239 
    240  nsIntRect mDecoded MOZ_GUARDED_BY(mMonitor);
    241 
    242  bool mAborted MOZ_GUARDED_BY(mMonitor);
    243  bool mFinished MOZ_GUARDED_BY(mMonitor);
    244  bool mShouldRecycle MOZ_GUARDED_BY(mMonitor);
    245 
    246  //////////////////////////////////////////////////////////////////////////////
    247  // Effectively const data, only mutated in the Init methods.
    248  //////////////////////////////////////////////////////////////////////////////
    249 
    250  //! The size of the buffer we are decoding to.
    251  IntSize mImageSize;
    252 
    253  //! The contents for the frame, as represented in the encoded image. This may
    254  //! differ from mImageSize because it may be a partial frame. For the first
    255  //! frame, this means we need to shift the data in place, and for animated
    256  //! frames, it likely need to combine with a previous frame to get the full
    257  //! contents.
    258  IntRect mBlendRect;
    259 
    260  //! This is the region that has changed between this frame and the previous
    261  //! frame of an animation. For the first frame, this will be the same as
    262  //! mFrameRect.
    263  IntRect mDirtyRect;
    264 
    265  //! The timeout for this frame.
    266  FrameTimeout mTimeout;
    267 
    268  DisposalMethod mDisposalMethod;
    269  BlendMethod mBlendMethod;
    270  SurfaceFormat mFormat;
    271 
    272  bool mNonPremult;
    273 };
    274 
    275 /**
    276 * A reference to an imgFrame that holds the imgFrame's surface in memory,
    277 * allowing drawing. If you have a DrawableFrameRef |ref| and |if (ref)| returns
    278 * true, then calls to Draw() and GetSourceSurface() are guaranteed to succeed.
    279 */
    280 class DrawableFrameRef final {
    281  typedef gfx::DataSourceSurface DataSourceSurface;
    282 
    283 public:
    284  DrawableFrameRef() = default;
    285 
    286  explicit DrawableFrameRef(imgFrame* aFrame) : mFrame(aFrame) {
    287    MOZ_ASSERT(aFrame);
    288    MonitorAutoLock lock(aFrame->mMonitor);
    289 
    290    if (aFrame->mRawSurface) {
    291      mRef.emplace(aFrame->mRawSurface, DataSourceSurface::READ);
    292      if (!mRef->IsMapped()) {
    293        mFrame = nullptr;
    294        mRef.reset();
    295      }
    296    } else if (!aFrame->mOptSurface || !aFrame->mOptSurface->IsValid()) {
    297      // The optimized surface has become invalid, so we need to redecode.
    298      // For example, on Windows, there may have been a device reset, and
    299      // all D2D surfaces now need to be recreated.
    300      mFrame = nullptr;
    301    }
    302  }
    303 
    304  DrawableFrameRef(DrawableFrameRef&& aOther)
    305      : mFrame(std::move(aOther.mFrame)), mRef(std::move(aOther.mRef)) {}
    306 
    307  DrawableFrameRef& operator=(DrawableFrameRef&& aOther) {
    308    MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
    309    mFrame = std::move(aOther.mFrame);
    310    mRef = std::move(aOther.mRef);
    311    return *this;
    312  }
    313 
    314  explicit operator bool() const { return bool(mFrame); }
    315 
    316  imgFrame* operator->() {
    317    MOZ_ASSERT(mFrame);
    318    return mFrame;
    319  }
    320 
    321  const imgFrame* operator->() const {
    322    MOZ_ASSERT(mFrame);
    323    return mFrame;
    324  }
    325 
    326  imgFrame* get() { return mFrame; }
    327  const imgFrame* get() const { return mFrame; }
    328 
    329  void reset() {
    330    mFrame = nullptr;
    331    mRef.reset();
    332  }
    333 
    334 private:
    335  DrawableFrameRef(const DrawableFrameRef& aOther) = delete;
    336  DrawableFrameRef& operator=(const DrawableFrameRef& aOther) = delete;
    337 
    338  RefPtr<imgFrame> mFrame;
    339  Maybe<DataSourceSurface::ScopedMap> mRef;
    340 };
    341 
    342 /**
    343 * A reference to an imgFrame that holds the imgFrame's surface in memory in a
    344 * format appropriate for access as raw data. If you have a RawAccessFrameRef
    345 * |ref| and |if (ref)| is true, then calls to GetImageData() is guaranteed to
    346 * succeed. This guarantee is stronger than DrawableFrameRef, so everything that
    347 * a valid DrawableFrameRef guarantees is also guaranteed by a valid
    348 * RawAccessFrameRef.
    349 *
    350 * This may be considerably more expensive than is necessary just for drawing,
    351 * so only use this when you need to read or write the raw underlying image data
    352 * that the imgFrame holds.
    353 *
    354 * Once all an imgFrame's RawAccessFrameRefs go out of scope, new
    355 * RawAccessFrameRefs cannot be created.
    356 */
    357 class RawAccessFrameRef final {
    358 public:
    359  RawAccessFrameRef() = default;
    360 
    361  explicit RawAccessFrameRef(imgFrame* aFrame,
    362                             gfx::DataSourceSurface::MapType aMapType)
    363      : mFrame(aFrame) {
    364    MOZ_ASSERT(mFrame, "Need a frame");
    365 
    366    // Note that we do not use ScopedMap here because it holds a strong
    367    // reference to the underlying surface. This affects the reuse logic for
    368    // recycling in imgFrame::InitForDecoderRecycle.
    369    {
    370      MonitorAutoLock lock(mFrame->mMonitor);
    371      gfx::DataSourceSurface::MappedSurface map;
    372      if (mFrame->mRawSurface && mFrame->mRawSurface->Map(aMapType, &map)) {
    373        MOZ_ASSERT(map.mData);
    374        mData = map.mData;
    375      }
    376    }
    377 
    378    if (!mData) {
    379      mFrame = nullptr;
    380    }
    381  }
    382 
    383  RawAccessFrameRef(RawAccessFrameRef&& aOther)
    384      : mFrame(std::move(aOther.mFrame)), mData(aOther.mData) {
    385    aOther.mData = nullptr;
    386  }
    387 
    388  ~RawAccessFrameRef() { reset(); }
    389 
    390  RawAccessFrameRef& operator=(RawAccessFrameRef&& aOther) {
    391    MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
    392 
    393    if (mFrame) {
    394      MonitorAutoLock lock(mFrame->mMonitor);
    395      mFrame->mRawSurface->Unmap();
    396    }
    397    mFrame = std::move(aOther.mFrame);
    398    mData = aOther.mData;
    399    aOther.mData = nullptr;
    400 
    401    return *this;
    402  }
    403 
    404  explicit operator bool() const { return bool(mFrame); }
    405 
    406  imgFrame* operator->() {
    407    MOZ_ASSERT(mFrame);
    408    return mFrame.get();
    409  }
    410 
    411  const imgFrame* operator->() const {
    412    MOZ_ASSERT(mFrame);
    413    return mFrame;
    414  }
    415 
    416  imgFrame* get() { return mFrame; }
    417  const imgFrame* get() const { return mFrame; }
    418 
    419  void reset() {
    420    if (mFrame) {
    421      MonitorAutoLock lock(mFrame->mMonitor);
    422      mFrame->mRawSurface->Unmap();
    423    }
    424    mFrame = nullptr;
    425    mData = nullptr;
    426  }
    427 
    428  uint8_t* Data() const { return mData; }
    429 
    430 private:
    431  RawAccessFrameRef(const RawAccessFrameRef& aOther) = delete;
    432  RawAccessFrameRef& operator=(const RawAccessFrameRef& aOther) = delete;
    433 
    434  RefPtr<imgFrame> mFrame;
    435  uint8_t* mData = nullptr;
    436 };
    437 
    438 }  // namespace image
    439 }  // namespace mozilla
    440 
    441 #endif  // mozilla_image_imgFrame_h