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