123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- /**
- * An interface for objects which can either store a surface or dynamically
- * generate one, and various implementations.
- */
- #ifndef mozilla_image_ISurfaceProvider_h
- #define mozilla_image_ISurfaceProvider_h
- #include "mozilla/Attributes.h"
- #include "mozilla/Maybe.h"
- #include "mozilla/MemoryReporting.h"
- #include "mozilla/NotNull.h"
- #include "mozilla/TimeStamp.h"
- #include "mozilla/Variant.h"
- #include "mozilla/gfx/2D.h"
- #include "imgFrame.h"
- #include "SurfaceCache.h"
- namespace mozilla {
- namespace image {
- class CachedSurface;
- class DrawableSurface;
- /**
- * An interface for objects which can either store a surface or dynamically
- * generate one.
- */
- class ISurfaceProvider
- {
- public:
- // Subclasses may or may not be XPCOM classes, so we just require that they
- // implement AddRef and Release.
- NS_IMETHOD_(MozExternalRefCountType) AddRef() = 0;
- NS_IMETHOD_(MozExternalRefCountType) Release() = 0;
- /// @return key data used for identifying which image this ISurfaceProvider is
- /// associated with in the surface cache.
- ImageKey GetImageKey() const { return mImageKey; }
- /// @return key data used to uniquely identify this ISurfaceProvider's cache
- /// entry in the surface cache.
- const SurfaceKey& GetSurfaceKey() const { return mSurfaceKey; }
- /// @return a (potentially lazily computed) drawable reference to a surface.
- virtual DrawableSurface Surface();
- /// @return true if DrawableRef() will return a completely decoded surface.
- virtual bool IsFinished() const = 0;
- /// @return the number of bytes of memory this ISurfaceProvider is expected to
- /// require. Optimizations may result in lower real memory usage. Trivial
- /// overhead is ignored. Because this value is used in bookkeeping, it's
- /// important that it be constant over the lifetime of this object.
- virtual size_t LogicalSizeInBytes() const = 0;
- /// @return the actual number of bytes of memory this ISurfaceProvider is
- /// using. May vary over the lifetime of the ISurfaceProvider. The default
- /// implementation is appropriate for static ISurfaceProviders.
- virtual void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
- size_t& aHeapSizeOut,
- size_t& aNonHeapSizeOut)
- {
- DrawableFrameRef ref = DrawableRef(/* aFrame = */ 0);
- if (!ref) {
- return;
- }
- ref->AddSizeOfExcludingThis(aMallocSizeOf, aHeapSizeOut, aNonHeapSizeOut);
- }
- /// @return the availability state of this ISurfaceProvider, which indicates
- /// whether DrawableRef() could successfully return a surface. Should only be
- /// called from SurfaceCache code as it relies on SurfaceCache for
- /// synchronization.
- AvailabilityState& Availability() { return mAvailability; }
- const AvailabilityState& Availability() const { return mAvailability; }
- protected:
- ISurfaceProvider(const ImageKey aImageKey,
- const SurfaceKey& aSurfaceKey,
- AvailabilityState aAvailability)
- : mImageKey(aImageKey)
- , mSurfaceKey(aSurfaceKey)
- , mAvailability(aAvailability)
- {
- MOZ_ASSERT(aImageKey, "Must have a valid image key");
- }
- virtual ~ISurfaceProvider() { }
- /// @return an eagerly computed drawable reference to a surface. For
- /// dynamically generated animation surfaces, @aFrame specifies the 0-based
- /// index of the desired frame.
- virtual DrawableFrameRef DrawableRef(size_t aFrame) = 0;
- /// @return true if this ISurfaceProvider is locked. (@see SetLocked())
- /// Should only be called from SurfaceCache code as it relies on SurfaceCache
- /// for synchronization.
- virtual bool IsLocked() const = 0;
- /// If @aLocked is true, hint that this ISurfaceProvider is in use and it
- /// should avoid releasing its resources. Should only be called from
- /// SurfaceCache code as it relies on SurfaceCache for synchronization.
- virtual void SetLocked(bool aLocked) = 0;
- private:
- friend class CachedSurface;
- friend class DrawableSurface;
- const ImageKey mImageKey;
- const SurfaceKey mSurfaceKey;
- AvailabilityState mAvailability;
- };
- /**
- * A reference to a surface (stored in an imgFrame) that holds the surface in
- * memory, guaranteeing that it can be drawn. If you have a DrawableSurface
- * |surf| and |if (surf)| returns true, then calls to |surf->Draw()| and
- * |surf->GetSourceSurface()| are guaranteed to succeed.
- *
- * Note that the surface may be computed lazily, so a DrawableSurface should not
- * be dereferenced (i.e., operator->() should not be called) until you're
- * sure that you want to draw it.
- */
- class MOZ_STACK_CLASS DrawableSurface final
- {
- public:
- DrawableSurface() : mHaveSurface(false) { }
- explicit DrawableSurface(DrawableFrameRef&& aDrawableRef)
- : mDrawableRef(Move(aDrawableRef))
- , mHaveSurface(bool(mDrawableRef))
- { }
- explicit DrawableSurface(NotNull<ISurfaceProvider*> aProvider)
- : mProvider(aProvider)
- , mHaveSurface(true)
- { }
- DrawableSurface(DrawableSurface&& aOther)
- : mDrawableRef(Move(aOther.mDrawableRef))
- , mProvider(Move(aOther.mProvider))
- , mHaveSurface(aOther.mHaveSurface)
- {
- aOther.mHaveSurface = false;
- }
- DrawableSurface& operator=(DrawableSurface&& aOther)
- {
- MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
- mDrawableRef = Move(aOther.mDrawableRef);
- mProvider = Move(aOther.mProvider);
- mHaveSurface = aOther.mHaveSurface;
- aOther.mHaveSurface = false;
- return *this;
- }
- /**
- * If this DrawableSurface is dynamically generated from an animation, attempt
- * to seek to frame @aFrame, where @aFrame is a 0-based index into the frames
- * of the animation. Otherwise, nothing will blow up at runtime, but we assert
- * in debug builds, since calling this in an unexpected situation probably
- * indicates a bug.
- *
- * @return a successful result if we could obtain frame @aFrame. Note that
- * |mHaveSurface| being true means that we're guaranteed to have *some* frame,
- * so the caller can dereference this DrawableSurface even if Seek() fails,
- * but while nothing will blow up, the frame won't be the one they expect.
- */
- nsresult Seek(size_t aFrame)
- {
- MOZ_ASSERT(mHaveSurface, "Trying to seek an empty DrawableSurface?");
- if (!mProvider) {
- MOZ_ASSERT_UNREACHABLE("Trying to seek a static DrawableSurface?");
- return NS_ERROR_FAILURE;
- }
- mDrawableRef = mProvider->DrawableRef(aFrame);
- return mDrawableRef ? NS_OK : NS_ERROR_FAILURE;
- }
- explicit operator bool() const { return mHaveSurface; }
- imgFrame* operator->() { return DrawableRef().get(); }
- private:
- DrawableSurface(const DrawableSurface& aOther) = delete;
- DrawableSurface& operator=(const DrawableSurface& aOther) = delete;
- DrawableFrameRef& DrawableRef()
- {
- MOZ_ASSERT(mHaveSurface);
- // If we weren't created with a DrawableFrameRef directly, we should've been
- // created with an ISurfaceProvider which can give us one. Note that if
- // Seek() has been called, we'll already have a DrawableFrameRef, so we
- // won't need to get one here.
- if (!mDrawableRef) {
- MOZ_ASSERT(mProvider);
- mDrawableRef = mProvider->DrawableRef(/* aFrame = */ 0);
- }
- MOZ_ASSERT(mDrawableRef);
- return mDrawableRef;
- }
- DrawableFrameRef mDrawableRef;
- RefPtr<ISurfaceProvider> mProvider;
- bool mHaveSurface;
- };
- // Surface() is implemented here so that DrawableSurface's definition is
- // visible. This default implementation eagerly obtains a DrawableFrameRef for
- // the first frame and is intended for static ISurfaceProviders.
- inline DrawableSurface
- ISurfaceProvider::Surface()
- {
- return DrawableSurface(DrawableRef(/* aFrame = */ 0));
- }
- /**
- * An ISurfaceProvider that stores a single surface.
- */
- class SimpleSurfaceProvider final : public ISurfaceProvider
- {
- public:
- NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SimpleSurfaceProvider, override)
- SimpleSurfaceProvider(const ImageKey aImageKey,
- const SurfaceKey& aSurfaceKey,
- NotNull<imgFrame*> aSurface)
- : ISurfaceProvider(aImageKey, aSurfaceKey,
- AvailabilityState::StartAvailable())
- , mSurface(aSurface)
- {
- MOZ_ASSERT(aSurfaceKey.Size() == mSurface->GetSize());
- }
- bool IsFinished() const override { return mSurface->IsFinished(); }
- size_t LogicalSizeInBytes() const override
- {
- gfx::IntSize size = mSurface->GetSize();
- return size.width * size.height * mSurface->GetBytesPerPixel();
- }
- protected:
- DrawableFrameRef DrawableRef(size_t aFrame) override
- {
- MOZ_ASSERT(aFrame == 0,
- "Requesting an animation frame from a SimpleSurfaceProvider?");
- return mSurface->DrawableRef();
- }
- bool IsLocked() const override { return bool(mLockRef); }
- void SetLocked(bool aLocked) override
- {
- if (aLocked == IsLocked()) {
- return; // Nothing changed.
- }
- // If we're locked, hold a DrawableFrameRef to |mSurface|, which will keep
- // any volatile buffer it owns in memory.
- mLockRef = aLocked ? mSurface->DrawableRef()
- : DrawableFrameRef();
- }
- private:
- virtual ~SimpleSurfaceProvider() { }
- NotNull<RefPtr<imgFrame>> mSurface;
- DrawableFrameRef mLockRef;
- };
- } // namespace image
- } // namespace mozilla
- #endif // mozilla_image_ISurfaceProvider_h
|