michael@0: /* -*- Mode: C++; tab-width: 20; 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: #ifndef MASKLAYERIMAGECACHE_H_ michael@0: #define MASKLAYERIMAGECACHE_H_ michael@0: michael@0: #include "DisplayItemClip.h" michael@0: #include "nsPresContext.h" michael@0: #include "mozilla/gfx/Matrix.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: namespace layers { michael@0: class ImageContainer; michael@0: } michael@0: michael@0: /** michael@0: * Keeps a record of image containers for mask layers, containers are mapped michael@0: * from the rounded rects used to create them. michael@0: * The cache stores MaskLayerImageEntries indexed by MaskLayerImageKeys. michael@0: * Each MaskLayerImageEntry owns a heap-allocated MaskLayerImageKey michael@0: * (heap-allocated so that a mask layer's userdata can keep a pointer to the michael@0: * key for its image, in spite of the hashtable moving its entries around). michael@0: * The key consists of the rounded rects used to create the mask, michael@0: * an nsRefPtr to the ImageContainer containing the image, and a count michael@0: * of the number of layers currently using this ImageContainer. michael@0: * When the key's layer count is zero, the cache michael@0: * may remove the entry, which deletes the key object. michael@0: */ michael@0: class MaskLayerImageCache michael@0: { michael@0: typedef mozilla::layers::ImageContainer ImageContainer; michael@0: public: michael@0: MaskLayerImageCache(); michael@0: ~MaskLayerImageCache(); michael@0: michael@0: /** michael@0: * Representation of a rounded rectangle in device pixel coordinates, in michael@0: * contrast to DisplayItemClip::RoundedRect, which uses app units. michael@0: * In particular, our internal representation uses a gfxRect, rather than michael@0: * an nsRect, so this class is easier to use with transforms. michael@0: */ michael@0: struct PixelRoundedRect michael@0: { michael@0: PixelRoundedRect(const DisplayItemClip::RoundedRect& aRRect, michael@0: nsPresContext* aPresContext) michael@0: : mRect(aPresContext->AppUnitsToGfxUnits(aRRect.mRect.x), michael@0: aPresContext->AppUnitsToGfxUnits(aRRect.mRect.y), michael@0: aPresContext->AppUnitsToGfxUnits(aRRect.mRect.width), michael@0: aPresContext->AppUnitsToGfxUnits(aRRect.mRect.height)) michael@0: { michael@0: MOZ_COUNT_CTOR(PixelRoundedRect); michael@0: NS_FOR_CSS_HALF_CORNERS(corner) { michael@0: mRadii[corner] = aPresContext->AppUnitsToGfxUnits(aRRect.mRadii[corner]); michael@0: } michael@0: } michael@0: PixelRoundedRect(const PixelRoundedRect& aPRR) michael@0: : mRect(aPRR.mRect) michael@0: { michael@0: MOZ_COUNT_CTOR(PixelRoundedRect); michael@0: NS_FOR_CSS_HALF_CORNERS(corner) { michael@0: mRadii[corner] = aPRR.mRadii[corner]; michael@0: } michael@0: } michael@0: michael@0: ~PixelRoundedRect() michael@0: { michael@0: MOZ_COUNT_DTOR(PixelRoundedRect); michael@0: } michael@0: michael@0: // Applies the scale and translate components of aTransform. michael@0: // It is an error to pass a matrix which does more than just scale michael@0: // and translate. michael@0: void ScaleAndTranslate(const gfx::Matrix& aTransform) michael@0: { michael@0: NS_ASSERTION(aTransform._12 == 0 && aTransform._21 == 0, michael@0: "Transform has a component other than scale and translate"); michael@0: michael@0: mRect = aTransform.TransformBounds(mRect); michael@0: michael@0: for (size_t i = 0; i < ArrayLength(mRadii); i += 2) { michael@0: mRadii[i] *= aTransform._11; michael@0: mRadii[i + 1] *= aTransform._22; michael@0: } michael@0: } michael@0: michael@0: bool operator==(const PixelRoundedRect& aOther) const { michael@0: if (!mRect.IsEqualInterior(aOther.mRect)) { michael@0: return false; michael@0: } michael@0: michael@0: NS_FOR_CSS_HALF_CORNERS(corner) { michael@0: if (mRadii[corner] != aOther.mRadii[corner]) { michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: bool operator!=(const PixelRoundedRect& aOther) const { michael@0: return !(*this == aOther); michael@0: } michael@0: michael@0: // Create a hash for this object. michael@0: PLDHashNumber Hash() const michael@0: { michael@0: PLDHashNumber hash = HashBytes(&mRect.x, 4*sizeof(gfxFloat)); michael@0: hash = AddToHash(hash, HashBytes(mRadii, 8*sizeof(gfxFloat))); michael@0: michael@0: return hash; michael@0: } michael@0: michael@0: gfx::Rect mRect; michael@0: // Indices into mRadii are the NS_CORNER_* constants in nsStyleConsts.h michael@0: gfxFloat mRadii[8]; michael@0: michael@0: private: michael@0: PixelRoundedRect() MOZ_DELETE; michael@0: }; michael@0: michael@0: /** michael@0: * A key to identify cached image containers. michael@0: * The const-ness of this class is with respect to its use as a key into a michael@0: * hashtable, so anything not used to create the hash is mutable. michael@0: * mLayerCount counts the number of mask layers which have a reference to michael@0: * MaskLayerImageEntry::mContainer; it is maintained by MaskLayerUserData, michael@0: * which keeps a reference to the key. There will usually be mLayerCount + 1 michael@0: * pointers to a key object (the +1 being from the hashtable entry), but this michael@0: * invariant may be temporarily broken. michael@0: */ michael@0: struct MaskLayerImageKey michael@0: { michael@0: MaskLayerImageKey() michael@0: : mLayerCount(0) michael@0: , mRoundedClipRects() michael@0: { michael@0: MOZ_COUNT_CTOR(MaskLayerImageKey); michael@0: } michael@0: MaskLayerImageKey(const MaskLayerImageKey& aKey) michael@0: : mLayerCount(aKey.mLayerCount) michael@0: , mRoundedClipRects(aKey.mRoundedClipRects) michael@0: { michael@0: MOZ_COUNT_CTOR(MaskLayerImageKey); michael@0: } michael@0: michael@0: ~MaskLayerImageKey() michael@0: { michael@0: MOZ_COUNT_DTOR(MaskLayerImageKey); michael@0: } michael@0: michael@0: void AddRef() const { ++mLayerCount; } michael@0: void Release() const michael@0: { michael@0: NS_ASSERTION(mLayerCount > 0, "Inconsistent layer count"); michael@0: --mLayerCount; michael@0: } michael@0: michael@0: PLDHashNumber Hash() const michael@0: { michael@0: PLDHashNumber hash = 0; michael@0: michael@0: for (uint32_t i = 0; i < mRoundedClipRects.Length(); ++i) { michael@0: hash = AddToHash(hash, mRoundedClipRects[i].Hash()); michael@0: } michael@0: michael@0: return hash; michael@0: } michael@0: michael@0: bool operator==(const MaskLayerImageKey& aOther) const michael@0: { michael@0: return mRoundedClipRects == aOther.mRoundedClipRects; michael@0: } michael@0: michael@0: mutable uint32_t mLayerCount; michael@0: nsTArray mRoundedClipRects; michael@0: }; michael@0: michael@0: michael@0: // Find an image container for aKey, returns nullptr if there is no suitable michael@0: // cached image. If there is an image, then aKey is set to point at the stored michael@0: // key for the image. michael@0: ImageContainer* FindImageFor(const MaskLayerImageKey** aKey); michael@0: michael@0: // Add an image container with a key to the cache michael@0: // The image container used will be set as the container in aKey and aKey michael@0: // itself will be linked from this cache michael@0: void PutImage(const MaskLayerImageKey* aKey, michael@0: ImageContainer* aContainer); michael@0: michael@0: // Sweep the cache for old image containers that can be deleted michael@0: void Sweep(); michael@0: michael@0: protected: michael@0: michael@0: class MaskLayerImageEntry : public PLDHashEntryHdr michael@0: { michael@0: public: michael@0: typedef const MaskLayerImageKey& KeyType; michael@0: typedef const MaskLayerImageKey* KeyTypePointer; michael@0: michael@0: MaskLayerImageEntry(KeyTypePointer aKey) : mKey(aKey) michael@0: { michael@0: MOZ_COUNT_CTOR(MaskLayerImageEntry); michael@0: } michael@0: MaskLayerImageEntry(const MaskLayerImageEntry& aOther) michael@0: : mKey(aOther.mKey.get()) michael@0: { michael@0: NS_ERROR("ALLOW_MEMMOVE == true, should never be called"); michael@0: } michael@0: ~MaskLayerImageEntry() michael@0: { michael@0: MOZ_COUNT_DTOR(MaskLayerImageEntry); michael@0: } michael@0: michael@0: // KeyEquals(): does this entry match this key? michael@0: bool KeyEquals(KeyTypePointer aKey) const michael@0: { michael@0: return *mKey == *aKey; michael@0: } michael@0: michael@0: // KeyToPointer(): Convert KeyType to KeyTypePointer michael@0: static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } michael@0: michael@0: // HashKey(): calculate the hash number michael@0: static PLDHashNumber HashKey(KeyTypePointer aKey) michael@0: { michael@0: return aKey->Hash(); michael@0: } michael@0: michael@0: // ALLOW_MEMMOVE can we move this class with memmove(), or do we have michael@0: // to use the copy constructor? michael@0: enum { ALLOW_MEMMOVE = true }; michael@0: michael@0: bool operator==(const MaskLayerImageEntry& aOther) const michael@0: { michael@0: return KeyEquals(aOther.mKey); michael@0: } michael@0: michael@0: nsAutoPtr mKey; michael@0: nsRefPtr mContainer; michael@0: }; michael@0: michael@0: nsTHashtable mMaskImageContainers; michael@0: michael@0: // helper funtion for Sweep(), called for each entry in the hashtable michael@0: static PLDHashOperator SweepFunc(MaskLayerImageEntry* aEntry, void* aUserArg); michael@0: }; michael@0: michael@0: } michael@0: michael@0: michael@0: #endif