Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #ifndef MASKLAYERIMAGECACHE_H_
7 : #define MASKLAYERIMAGECACHE_H_
8 :
9 : #include "DisplayItemClip.h"
10 : #include "nsAutoPtr.h"
11 : #include "nsPresContext.h"
12 : #include "mozilla/gfx/Matrix.h"
13 :
14 : namespace mozilla {
15 :
16 : namespace layers {
17 : class ImageContainer;
18 : class ShadowLayerForwarder;
19 : } // namespace layers
20 :
21 : /**
22 : * Keeps a record of image containers for mask layers, containers are mapped
23 : * from the rounded rects used to create them.
24 : * The cache stores MaskLayerImageEntries indexed by MaskLayerImageKeys.
25 : * Each MaskLayerImageEntry owns a heap-allocated MaskLayerImageKey
26 : * (heap-allocated so that a mask layer's userdata can keep a pointer to the
27 : * key for its image, in spite of the hashtable moving its entries around).
28 : * The key consists of the rounded rects used to create the mask,
29 : * an nsRefPtr to the ImageContainer containing the image, and a count
30 : * of the number of layers currently using this ImageContainer.
31 : * When the key's layer count is zero, the cache
32 : * may remove the entry, which deletes the key object.
33 : */
34 : class MaskLayerImageCache
35 : {
36 : typedef mozilla::layers::ImageContainer ImageContainer;
37 : typedef mozilla::layers::ShadowLayerForwarder ShadowLayerForwarder;
38 : public:
39 : MaskLayerImageCache();
40 : ~MaskLayerImageCache();
41 :
42 : /**
43 : * Representation of a rounded rectangle in device pixel coordinates, in
44 : * contrast to DisplayItemClip::RoundedRect, which uses app units.
45 : * In particular, our internal representation uses a gfxRect, rather than
46 : * an nsRect, so this class is easier to use with transforms.
47 : */
48 : struct PixelRoundedRect
49 : {
50 0 : PixelRoundedRect(const DisplayItemClip::RoundedRect& aRRect,
51 : nsPresContext* aPresContext)
52 0 : : mRect(aPresContext->AppUnitsToGfxUnits(aRRect.mRect.x),
53 0 : aPresContext->AppUnitsToGfxUnits(aRRect.mRect.y),
54 0 : aPresContext->AppUnitsToGfxUnits(aRRect.mRect.width),
55 0 : aPresContext->AppUnitsToGfxUnits(aRRect.mRect.height))
56 : {
57 0 : MOZ_COUNT_CTOR(PixelRoundedRect);
58 0 : NS_FOR_CSS_HALF_CORNERS(corner) {
59 0 : mRadii[corner] = aPresContext->AppUnitsToGfxUnits(aRRect.mRadii[corner]);
60 : }
61 0 : }
62 0 : PixelRoundedRect(const PixelRoundedRect& aPRR)
63 0 : : mRect(aPRR.mRect)
64 : {
65 0 : MOZ_COUNT_CTOR(PixelRoundedRect);
66 0 : NS_FOR_CSS_HALF_CORNERS(corner) {
67 0 : mRadii[corner] = aPRR.mRadii[corner];
68 : }
69 0 : }
70 :
71 0 : ~PixelRoundedRect()
72 0 : {
73 0 : MOZ_COUNT_DTOR(PixelRoundedRect);
74 0 : }
75 :
76 : // Applies the scale and translate components of aTransform.
77 : // It is an error to pass a matrix which does more than just scale
78 : // and translate.
79 0 : void ScaleAndTranslate(const gfx::Matrix& aTransform)
80 : {
81 0 : NS_ASSERTION(aTransform._12 == 0 && aTransform._21 == 0,
82 : "Transform has a component other than scale and translate");
83 :
84 0 : mRect = aTransform.TransformBounds(mRect);
85 :
86 0 : for (size_t i = 0; i < ArrayLength(mRadii); i += 2) {
87 0 : mRadii[i] *= aTransform._11;
88 0 : mRadii[i + 1] *= aTransform._22;
89 : }
90 0 : }
91 :
92 0 : bool operator==(const PixelRoundedRect& aOther) const {
93 0 : if (!mRect.IsEqualInterior(aOther.mRect)) {
94 0 : return false;
95 : }
96 :
97 0 : NS_FOR_CSS_HALF_CORNERS(corner) {
98 0 : if (mRadii[corner] != aOther.mRadii[corner]) {
99 0 : return false;
100 : }
101 : }
102 0 : return true;
103 : }
104 : bool operator!=(const PixelRoundedRect& aOther) const {
105 : return !(*this == aOther);
106 : }
107 :
108 : // Create a hash for this object.
109 0 : PLDHashNumber Hash() const
110 : {
111 0 : PLDHashNumber hash = HashBytes(&mRect.x, 4*sizeof(gfxFloat));
112 0 : hash = AddToHash(hash, HashBytes(mRadii, 8*sizeof(gfxFloat)));
113 :
114 0 : return hash;
115 : }
116 :
117 : gfx::Rect mRect;
118 : // Indices into mRadii are the enum HalfCorner constants in gfx/2d/Types.h
119 : gfxFloat mRadii[8];
120 :
121 : private:
122 : PixelRoundedRect() = delete;
123 : };
124 :
125 : struct MaskLayerImageKeyRef;
126 :
127 : /**
128 : * A key to identify cached image containers.
129 : * The const-ness of this class is with respect to its use as a key into a
130 : * hashtable, so anything not used to create the hash is mutable.
131 : * mLayerCount counts the number of mask layers which have a reference to
132 : * MaskLayerImageEntry::mContainer; it is maintained by MaskLayerUserData,
133 : * which keeps a reference to the key. There will usually be mLayerCount + 1
134 : * pointers to a key object (the +1 being from the hashtable entry), but this
135 : * invariant may be temporarily broken.
136 : */
137 : struct MaskLayerImageKey
138 : {
139 : friend struct MaskLayerImageKeyRef;
140 :
141 : MaskLayerImageKey();
142 : MaskLayerImageKey(const MaskLayerImageKey& aKey);
143 :
144 : ~MaskLayerImageKey();
145 :
146 0 : bool HasZeroLayerCount() const {
147 0 : return mLayerCount == 0;
148 : }
149 :
150 0 : PLDHashNumber Hash() const
151 : {
152 0 : PLDHashNumber hash = 0;
153 :
154 0 : for (uint32_t i = 0; i < mRoundedClipRects.Length(); ++i) {
155 0 : hash = AddToHash(hash, mRoundedClipRects[i].Hash());
156 : }
157 0 : hash = AddToHash(hash, mForwarder.get());
158 :
159 0 : return hash;
160 : }
161 :
162 0 : bool operator==(const MaskLayerImageKey& aOther) const
163 : {
164 0 : return mForwarder == aOther.mForwarder &&
165 0 : mRoundedClipRects == aOther.mRoundedClipRects;
166 : }
167 :
168 : nsTArray<PixelRoundedRect> mRoundedClipRects;
169 : RefPtr<ShadowLayerForwarder> mForwarder;
170 : private:
171 0 : void IncLayerCount() const { ++mLayerCount; }
172 0 : void DecLayerCount() const
173 : {
174 0 : NS_ASSERTION(mLayerCount > 0, "Inconsistent layer count");
175 0 : --mLayerCount;
176 0 : }
177 : mutable uint32_t mLayerCount;
178 : };
179 :
180 : /**
181 : * This struct maintains a reference to a MaskLayerImageKey, via a variant on
182 : * refcounting. When a key is passed in via Reset(), we increment the
183 : * passed-in key's mLayerCount, and we decrement its mLayerCount when we're
184 : * destructed (or when the key is replaced via a second Reset() call).
185 : *
186 : * However, unlike standard refcounting smart-pointers, this object does
187 : * *not* delete the tracked MaskLayerImageKey -- instead, deletion happens
188 : * in MaskLayerImageCache::Sweep(), for any keys whose mLayerCount is 0.
189 : */
190 : struct MaskLayerImageKeyRef
191 : {
192 0 : ~MaskLayerImageKeyRef()
193 0 : {
194 0 : if (mRawPtr) {
195 0 : mRawPtr->DecLayerCount();
196 : }
197 0 : }
198 :
199 0 : MaskLayerImageKeyRef() : mRawPtr(nullptr) {}
200 : MaskLayerImageKeyRef(const MaskLayerImageKeyRef&) = delete;
201 : void operator=(const MaskLayerImageKeyRef&) = delete;
202 :
203 0 : void Reset(const MaskLayerImageKey* aPtr)
204 : {
205 0 : MOZ_ASSERT(aPtr, "Cannot initialize a MaskLayerImageKeyRef with a null pointer");
206 0 : aPtr->IncLayerCount();
207 0 : if (mRawPtr) {
208 0 : mRawPtr->DecLayerCount();
209 : }
210 0 : mRawPtr = aPtr;
211 0 : }
212 :
213 : private:
214 : const MaskLayerImageKey* mRawPtr;
215 : };
216 :
217 : // Find an image container for aKey, returns nullptr if there is no suitable
218 : // cached image. If there is an image, then aKey is set to point at the stored
219 : // key for the image.
220 : ImageContainer* FindImageFor(const MaskLayerImageKey** aKey);
221 :
222 : // Add an image container with a key to the cache
223 : // The image container used will be set as the container in aKey and aKey
224 : // itself will be linked from this cache
225 : void PutImage(const MaskLayerImageKey* aKey,
226 : ImageContainer* aContainer);
227 :
228 : // Sweep the cache for old image containers that can be deleted
229 : void Sweep();
230 :
231 : protected:
232 :
233 : class MaskLayerImageEntry : public PLDHashEntryHdr
234 : {
235 : public:
236 : typedef const MaskLayerImageKey& KeyType;
237 : typedef const MaskLayerImageKey* KeyTypePointer;
238 :
239 0 : explicit MaskLayerImageEntry(KeyTypePointer aKey)
240 0 : : mKey(aKey)
241 : {
242 0 : MOZ_COUNT_CTOR(MaskLayerImageEntry);
243 0 : }
244 : MaskLayerImageEntry(const MaskLayerImageEntry& aOther)
245 : : mKey(aOther.mKey.get())
246 : {
247 : NS_ERROR("ALLOW_MEMMOVE == true, should never be called");
248 : }
249 0 : ~MaskLayerImageEntry()
250 0 : {
251 0 : MOZ_COUNT_DTOR(MaskLayerImageEntry);
252 0 : }
253 :
254 : // KeyEquals(): does this entry match this key?
255 0 : bool KeyEquals(KeyTypePointer aKey) const
256 : {
257 0 : return *mKey == *aKey;
258 : }
259 :
260 : // KeyToPointer(): Convert KeyType to KeyTypePointer
261 0 : static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
262 :
263 : // HashKey(): calculate the hash number
264 0 : static PLDHashNumber HashKey(KeyTypePointer aKey)
265 : {
266 0 : return aKey->Hash();
267 : }
268 :
269 : // ALLOW_MEMMOVE can we move this class with memmove(), or do we have
270 : // to use the copy constructor?
271 : enum { ALLOW_MEMMOVE = true };
272 :
273 : bool operator==(const MaskLayerImageEntry& aOther) const
274 : {
275 : return KeyEquals(aOther.mKey);
276 : }
277 :
278 : nsAutoPtr<const MaskLayerImageKey> mKey;
279 : RefPtr<ImageContainer> mContainer;
280 : };
281 :
282 : nsTHashtable<MaskLayerImageEntry> mMaskImageContainers;
283 : };
284 :
285 :
286 : } // namespace mozilla
287 :
288 :
289 : #endif
|