michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /** michael@0: * SurfaceCache is a service for caching temporary surfaces in imagelib. michael@0: */ michael@0: michael@0: #ifndef MOZILLA_IMAGELIB_SURFACECACHE_H_ michael@0: #define MOZILLA_IMAGELIB_SURFACECACHE_H_ michael@0: michael@0: #include "mozilla/HashFunctions.h" // for HashGeneric and AddToHash michael@0: #include "gfxPoint.h" // for gfxSize michael@0: #include "nsCOMPtr.h" // for already_AddRefed michael@0: #include "mozilla/gfx/Point.h" // for mozilla::gfx::IntSize michael@0: #include "SVGImageContext.h" // for SVGImageContext michael@0: michael@0: class gfxDrawable; michael@0: michael@0: namespace mozilla { michael@0: michael@0: namespace gfx { michael@0: class DrawTarget; michael@0: } // namespace gfx michael@0: michael@0: namespace image { michael@0: michael@0: class Image; michael@0: michael@0: /* michael@0: * ImageKey contains the information we need to look up all cached surfaces for michael@0: * a particular image. michael@0: */ michael@0: typedef Image* ImageKey; michael@0: michael@0: /* michael@0: * SurfaceKey contains the information we need to look up a specific cached michael@0: * surface. Together with an ImageKey, this uniquely identifies the surface. michael@0: * michael@0: * XXX(seth): Right now this is specialized to the needs of VectorImage. We'll michael@0: * generalize it in bug 919071. michael@0: */ michael@0: class SurfaceKey michael@0: { michael@0: typedef gfx::IntSize IntSize; michael@0: public: michael@0: SurfaceKey(const IntSize& aSize, michael@0: const gfxSize aScale, michael@0: const SVGImageContext* aSVGContext, michael@0: const float aAnimationTime, michael@0: const uint32_t aFlags) michael@0: : mSize(aSize) michael@0: , mScale(aScale) michael@0: , mSVGContextIsValid(aSVGContext != nullptr) michael@0: , mAnimationTime(aAnimationTime) michael@0: , mFlags(aFlags) michael@0: { michael@0: // XXX(seth): Would love to use Maybe here, but see bug 913586. michael@0: if (mSVGContextIsValid) michael@0: mSVGContext = *aSVGContext; michael@0: } michael@0: michael@0: bool operator==(const SurfaceKey& aOther) const michael@0: { michael@0: bool matchesSVGContext = aOther.mSVGContextIsValid == mSVGContextIsValid && michael@0: (!mSVGContextIsValid || aOther.mSVGContext == mSVGContext); michael@0: return aOther.mSize == mSize && michael@0: aOther.mScale == mScale && michael@0: matchesSVGContext && michael@0: aOther.mAnimationTime == mAnimationTime && michael@0: aOther.mFlags == mFlags; michael@0: } michael@0: michael@0: uint32_t Hash() const michael@0: { michael@0: uint32_t hash = HashGeneric(mSize.width, mSize.height); michael@0: hash = AddToHash(hash, mScale.width, mScale.height); michael@0: hash = AddToHash(hash, mSVGContextIsValid, mSVGContext.Hash()); michael@0: hash = AddToHash(hash, mAnimationTime, mFlags); michael@0: return hash; michael@0: } michael@0: michael@0: IntSize Size() const { return mSize; } michael@0: michael@0: private: michael@0: IntSize mSize; michael@0: gfxSize mScale; michael@0: SVGImageContext mSVGContext; michael@0: bool mSVGContextIsValid; michael@0: float mAnimationTime; michael@0: uint32_t mFlags; michael@0: }; michael@0: michael@0: /** michael@0: * SurfaceCache is an imagelib-global service that allows caching of temporary michael@0: * surfaces. Surfaces expire from the cache automatically if they go too long michael@0: * without being accessed. michael@0: * michael@0: * SurfaceCache is not thread-safe; it should only be accessed from the main michael@0: * thread. michael@0: */ michael@0: struct SurfaceCache michael@0: { michael@0: typedef gfx::IntSize IntSize; michael@0: michael@0: /* michael@0: * Initialize static data. Called during imagelib module initialization. michael@0: */ michael@0: static void Initialize(); michael@0: michael@0: /* michael@0: * Release static data. Called during imagelib module shutdown. michael@0: */ michael@0: static void Shutdown(); michael@0: michael@0: /* michael@0: * Look up a surface in the cache. michael@0: * michael@0: * @param aImageKey Key data identifying which image the surface belongs to. michael@0: * @param aSurfaceKey Key data which uniquely identifies the requested surface. michael@0: * michael@0: * @return the requested surface, or nullptr if not found. michael@0: */ michael@0: static already_AddRefed Lookup(const ImageKey aImageKey, michael@0: const SurfaceKey& aSurfaceKey); michael@0: michael@0: /* michael@0: * Insert a surface into the cache. It is an error to call this function michael@0: * without first calling Lookup to verify that the surface is not already in michael@0: * the cache. michael@0: * michael@0: * @param aTarget The new surface (in the form of a DrawTarget) to insert michael@0: * into the cache. michael@0: * @param aImageKey Key data identifying which image the surface belongs to. michael@0: * @param aSurfaceKey Key data which uniquely identifies the requested surface. michael@0: */ michael@0: static void Insert(mozilla::gfx::DrawTarget* aTarget, michael@0: const ImageKey aImageKey, michael@0: const SurfaceKey& aSurfaceKey); michael@0: michael@0: /* michael@0: * Checks if a surface of a given size could possibly be stored in the cache. michael@0: * If CanHold() returns false, Insert() will always fail to insert the michael@0: * surface, but the inverse is not true: Insert() may take more information michael@0: * into account than just image size when deciding whether to cache the michael@0: * surface, so Insert() may still fail even if CanHold() returns true. michael@0: * michael@0: * Use CanHold() to avoid the need to create a temporary surface when we know michael@0: * for sure the cache can't hold it. michael@0: * michael@0: * @param aSize The dimensions of a surface in pixels. michael@0: * michael@0: * @return false if the surface cache can't hold a surface of that size. michael@0: */ michael@0: static bool CanHold(const IntSize& aSize); michael@0: michael@0: /* michael@0: * Evicts any cached surfaces associated with the given image from the cache. michael@0: * This MUST be called, at a minimum, when the image is destroyed. If michael@0: * another image were allocated at the same address it could result in michael@0: * subtle, difficult-to-reproduce bugs. michael@0: * michael@0: * @param aImageKey The image which should be removed from the cache. michael@0: */ michael@0: static void Discard(const ImageKey aImageKey); michael@0: michael@0: /* michael@0: * Evicts all caches surfaces from ths cache. michael@0: */ michael@0: static void DiscardAll(); michael@0: michael@0: private: michael@0: virtual ~SurfaceCache() = 0; // Forbid instantiation. michael@0: }; michael@0: michael@0: } // namespace image michael@0: } // namespace mozilla michael@0: michael@0: #endif // MOZILLA_IMAGELIB_SURFACECACHE_H_