1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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/. */
7 #ifndef MASKLAYERIMAGECACHE_H_
8 #define MASKLAYERIMAGECACHE_H_
10 #include "DisplayItemClip.h"
11 #include "nsPresContext.h"
12 #include "mozilla/gfx/Matrix.h"
13 #include "mozilla/UniquePtr.h"
19 class KnowsCompositor
;
23 * Keeps a record of image containers for mask layers, containers are mapped
24 * from the rounded rects used to create them.
25 * The cache stores MaskLayerImageEntries indexed by MaskLayerImageKeys.
26 * Each MaskLayerImageEntry owns a heap-allocated MaskLayerImageKey
27 * (heap-allocated so that a mask layer's userdata can keep a pointer to the
28 * key for its image, in spite of the hashtable moving its entries around).
29 * The key consists of the rounded rects used to create the mask,
30 * an nsRefPtr to the ImageContainer containing the image, and a count
31 * of the number of layers currently using this ImageContainer.
32 * When the key's layer count is zero, the cache
33 * may remove the entry, which deletes the key object.
35 class MaskLayerImageCache
{
36 typedef mozilla::layers::ImageContainer ImageContainer
;
37 typedef mozilla::layers::KnowsCompositor KnowsCompositor
;
40 MaskLayerImageCache();
41 ~MaskLayerImageCache();
44 * Representation of a rounded rectangle in device pixel coordinates, in
45 * contrast to DisplayItemClip::RoundedRect, which uses app units.
46 * In particular, our internal representation uses a gfxRect, rather than
47 * an nsRect, so this class is easier to use with transforms.
49 struct PixelRoundedRect
{
50 PixelRoundedRect() = delete;
52 PixelRoundedRect(const DisplayItemClip::RoundedRect
& aRRect
,
53 nsPresContext
* aPresContext
)
54 : mRect(aPresContext
->AppUnitsToGfxUnits(aRRect
.mRect
.x
),
55 aPresContext
->AppUnitsToGfxUnits(aRRect
.mRect
.y
),
56 aPresContext
->AppUnitsToGfxUnits(aRRect
.mRect
.width
),
57 aPresContext
->AppUnitsToGfxUnits(aRRect
.mRect
.height
)) {
58 MOZ_COUNT_CTOR(PixelRoundedRect
);
59 for (const auto corner
: mozilla::AllPhysicalHalfCorners()) {
61 aPresContext
->AppUnitsToGfxUnits(aRRect
.mRadii
[corner
]);
65 PixelRoundedRect(const PixelRoundedRect
& aPRR
) : mRect(aPRR
.mRect
) {
66 MOZ_COUNT_CTOR(PixelRoundedRect
);
67 for (const auto corner
: mozilla::AllPhysicalHalfCorners()) {
68 mRadii
[corner
] = aPRR
.mRadii
[corner
];
72 MOZ_COUNTED_DTOR(PixelRoundedRect
)
74 // Applies the scale and translate components of aTransform.
75 // It is an error to pass a matrix which does more than just scale
77 void ScaleAndTranslate(const gfx::Matrix
& aTransform
) {
78 NS_ASSERTION(aTransform
._12
== 0 && aTransform
._21
== 0,
79 "Transform has a component other than scale and translate");
81 mRect
= aTransform
.TransformBounds(mRect
);
83 for (size_t i
= 0; i
< ArrayLength(mRadii
); i
+= 2) {
84 mRadii
[i
] *= aTransform
._11
;
85 mRadii
[i
+ 1] *= aTransform
._22
;
89 bool operator==(const PixelRoundedRect
& aOther
) const {
90 if (!mRect
.IsEqualInterior(aOther
.mRect
)) {
94 for (const auto corner
: mozilla::AllPhysicalHalfCorners()) {
95 if (mRadii
[corner
] != aOther
.mRadii
[corner
]) {
101 bool operator!=(const PixelRoundedRect
& aOther
) const {
102 return !(*this == aOther
);
105 // Create a hash for this object.
106 PLDHashNumber
Hash() const {
107 PLDHashNumber hash
= HashBytes(&mRect
.x
, 4 * sizeof(gfxFloat
));
108 hash
= AddToHash(hash
, HashBytes(mRadii
, 8 * sizeof(gfxFloat
)));
114 // Indices into mRadii are the enum HalfCorner constants in gfx/2d/Types.h
118 struct MaskLayerImageKeyRef
;
121 * A key to identify cached image containers.
122 * The const-ness of this class is with respect to its use as a key into a
123 * hashtable, so anything not used to create the hash is mutable.
124 * mLayerCount counts the number of mask layers which have a reference to
125 * MaskLayerImageEntry::mContainer; it is maintained by MaskLayerUserData,
126 * which keeps a reference to the key. There will usually be mLayerCount + 1
127 * pointers to a key object (the +1 being from the hashtable entry), but this
128 * invariant may be temporarily broken.
130 struct MaskLayerImageKey
{
131 friend struct MaskLayerImageKeyRef
;
134 MaskLayerImageKey(const MaskLayerImageKey
& aKey
);
136 ~MaskLayerImageKey();
138 bool HasZeroLayerCount() const { return mLayerCount
== 0; }
140 PLDHashNumber
Hash() const {
141 PLDHashNumber hash
= 0;
143 for (uint32_t i
= 0; i
< mRoundedClipRects
.Length(); ++i
) {
144 hash
= AddToHash(hash
, mRoundedClipRects
[i
].Hash());
146 hash
= AddToHash(hash
, mKnowsCompositor
.get());
151 bool operator==(const MaskLayerImageKey
& aOther
) const {
152 return mKnowsCompositor
== aOther
.mKnowsCompositor
&&
153 mRoundedClipRects
== aOther
.mRoundedClipRects
;
156 nsTArray
<PixelRoundedRect
> mRoundedClipRects
;
157 RefPtr
<KnowsCompositor
> mKnowsCompositor
;
160 void IncLayerCount() const { ++mLayerCount
; }
161 void DecLayerCount() const {
162 NS_ASSERTION(mLayerCount
> 0, "Inconsistent layer count");
165 mutable uint32_t mLayerCount
;
169 * This struct maintains a reference to a MaskLayerImageKey, via a variant on
170 * refcounting. When a key is passed in via Reset(), we increment the
171 * passed-in key's mLayerCount, and we decrement its mLayerCount when we're
172 * destructed (or when the key is replaced via a second Reset() call).
174 * However, unlike standard refcounting smart-pointers, this object does
175 * *not* delete the tracked MaskLayerImageKey -- instead, deletion happens
176 * in MaskLayerImageCache::Sweep(), for any keys whose mLayerCount is 0.
178 struct MaskLayerImageKeyRef
{
179 ~MaskLayerImageKeyRef() {
181 mRawPtr
->DecLayerCount();
185 MaskLayerImageKeyRef() : mRawPtr(nullptr) {}
186 MaskLayerImageKeyRef(const MaskLayerImageKeyRef
&) = delete;
187 void operator=(const MaskLayerImageKeyRef
&) = delete;
189 void Reset(const MaskLayerImageKey
* aPtr
) {
191 aPtr
, "Cannot initialize a MaskLayerImageKeyRef with a null pointer");
192 aPtr
->IncLayerCount();
194 mRawPtr
->DecLayerCount();
200 const MaskLayerImageKey
* mRawPtr
;
203 // Find an image container for aKey, returns nullptr if there is no suitable
204 // cached image. If there is an image, then aKey is set to point at the stored
205 // key for the image.
206 ImageContainer
* FindImageFor(const MaskLayerImageKey
** aKey
);
208 // Add an image container with a key to the cache
209 // The image container used will be set as the container in aKey and aKey
210 // itself will be linked from this cache
211 void PutImage(const MaskLayerImageKey
* aKey
, ImageContainer
* aContainer
);
213 // Sweep the cache for old image containers that can be deleted
217 class MaskLayerImageEntry
: public PLDHashEntryHdr
{
219 typedef const MaskLayerImageKey
& KeyType
;
220 typedef const MaskLayerImageKey
* KeyTypePointer
;
222 explicit MaskLayerImageEntry(KeyTypePointer aKey
) : mKey(aKey
) {
223 MOZ_COUNT_CTOR(MaskLayerImageEntry
);
225 MaskLayerImageEntry(const MaskLayerImageEntry
& aOther
)
226 : mKey(aOther
.mKey
.get()) {
227 NS_ERROR("ALLOW_MEMMOVE == true, should never be called");
229 MOZ_COUNTED_DTOR(MaskLayerImageEntry
)
231 // KeyEquals(): does this entry match this key?
232 bool KeyEquals(KeyTypePointer aKey
) const { return *mKey
== *aKey
; }
234 // KeyToPointer(): Convert KeyType to KeyTypePointer
235 static KeyTypePointer
KeyToPointer(KeyType aKey
) { return &aKey
; }
237 // HashKey(): calculate the hash number
238 static PLDHashNumber
HashKey(KeyTypePointer aKey
) { return aKey
->Hash(); }
240 // ALLOW_MEMMOVE can we move this class with memmove(), or do we have
241 // to use the copy constructor?
242 enum { ALLOW_MEMMOVE
= true };
244 bool operator==(const MaskLayerImageEntry
& aOther
) const {
245 return KeyEquals(aOther
.mKey
.get());
248 mozilla::UniquePtr
<const MaskLayerImageKey
> mKey
;
249 RefPtr
<ImageContainer
> mContainer
;
252 nsTHashtable
<MaskLayerImageEntry
> mMaskImageContainers
;
255 } // namespace mozilla