|
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 "nsPresContext.h" |
|
11 #include "mozilla/gfx/Matrix.h" |
|
12 |
|
13 namespace mozilla { |
|
14 |
|
15 namespace layers { |
|
16 class ImageContainer; |
|
17 } |
|
18 |
|
19 /** |
|
20 * Keeps a record of image containers for mask layers, containers are mapped |
|
21 * from the rounded rects used to create them. |
|
22 * The cache stores MaskLayerImageEntries indexed by MaskLayerImageKeys. |
|
23 * Each MaskLayerImageEntry owns a heap-allocated MaskLayerImageKey |
|
24 * (heap-allocated so that a mask layer's userdata can keep a pointer to the |
|
25 * key for its image, in spite of the hashtable moving its entries around). |
|
26 * The key consists of the rounded rects used to create the mask, |
|
27 * an nsRefPtr to the ImageContainer containing the image, and a count |
|
28 * of the number of layers currently using this ImageContainer. |
|
29 * When the key's layer count is zero, the cache |
|
30 * may remove the entry, which deletes the key object. |
|
31 */ |
|
32 class MaskLayerImageCache |
|
33 { |
|
34 typedef mozilla::layers::ImageContainer ImageContainer; |
|
35 public: |
|
36 MaskLayerImageCache(); |
|
37 ~MaskLayerImageCache(); |
|
38 |
|
39 /** |
|
40 * Representation of a rounded rectangle in device pixel coordinates, in |
|
41 * contrast to DisplayItemClip::RoundedRect, which uses app units. |
|
42 * In particular, our internal representation uses a gfxRect, rather than |
|
43 * an nsRect, so this class is easier to use with transforms. |
|
44 */ |
|
45 struct PixelRoundedRect |
|
46 { |
|
47 PixelRoundedRect(const DisplayItemClip::RoundedRect& aRRect, |
|
48 nsPresContext* aPresContext) |
|
49 : mRect(aPresContext->AppUnitsToGfxUnits(aRRect.mRect.x), |
|
50 aPresContext->AppUnitsToGfxUnits(aRRect.mRect.y), |
|
51 aPresContext->AppUnitsToGfxUnits(aRRect.mRect.width), |
|
52 aPresContext->AppUnitsToGfxUnits(aRRect.mRect.height)) |
|
53 { |
|
54 MOZ_COUNT_CTOR(PixelRoundedRect); |
|
55 NS_FOR_CSS_HALF_CORNERS(corner) { |
|
56 mRadii[corner] = aPresContext->AppUnitsToGfxUnits(aRRect.mRadii[corner]); |
|
57 } |
|
58 } |
|
59 PixelRoundedRect(const PixelRoundedRect& aPRR) |
|
60 : mRect(aPRR.mRect) |
|
61 { |
|
62 MOZ_COUNT_CTOR(PixelRoundedRect); |
|
63 NS_FOR_CSS_HALF_CORNERS(corner) { |
|
64 mRadii[corner] = aPRR.mRadii[corner]; |
|
65 } |
|
66 } |
|
67 |
|
68 ~PixelRoundedRect() |
|
69 { |
|
70 MOZ_COUNT_DTOR(PixelRoundedRect); |
|
71 } |
|
72 |
|
73 // Applies the scale and translate components of aTransform. |
|
74 // It is an error to pass a matrix which does more than just scale |
|
75 // and translate. |
|
76 void ScaleAndTranslate(const gfx::Matrix& aTransform) |
|
77 { |
|
78 NS_ASSERTION(aTransform._12 == 0 && aTransform._21 == 0, |
|
79 "Transform has a component other than scale and translate"); |
|
80 |
|
81 mRect = aTransform.TransformBounds(mRect); |
|
82 |
|
83 for (size_t i = 0; i < ArrayLength(mRadii); i += 2) { |
|
84 mRadii[i] *= aTransform._11; |
|
85 mRadii[i + 1] *= aTransform._22; |
|
86 } |
|
87 } |
|
88 |
|
89 bool operator==(const PixelRoundedRect& aOther) const { |
|
90 if (!mRect.IsEqualInterior(aOther.mRect)) { |
|
91 return false; |
|
92 } |
|
93 |
|
94 NS_FOR_CSS_HALF_CORNERS(corner) { |
|
95 if (mRadii[corner] != aOther.mRadii[corner]) { |
|
96 return false; |
|
97 } |
|
98 } |
|
99 return true; |
|
100 } |
|
101 bool operator!=(const PixelRoundedRect& aOther) const { |
|
102 return !(*this == aOther); |
|
103 } |
|
104 |
|
105 // Create a hash for this object. |
|
106 PLDHashNumber Hash() const |
|
107 { |
|
108 PLDHashNumber hash = HashBytes(&mRect.x, 4*sizeof(gfxFloat)); |
|
109 hash = AddToHash(hash, HashBytes(mRadii, 8*sizeof(gfxFloat))); |
|
110 |
|
111 return hash; |
|
112 } |
|
113 |
|
114 gfx::Rect mRect; |
|
115 // Indices into mRadii are the NS_CORNER_* constants in nsStyleConsts.h |
|
116 gfxFloat mRadii[8]; |
|
117 |
|
118 private: |
|
119 PixelRoundedRect() MOZ_DELETE; |
|
120 }; |
|
121 |
|
122 /** |
|
123 * A key to identify cached image containers. |
|
124 * The const-ness of this class is with respect to its use as a key into a |
|
125 * hashtable, so anything not used to create the hash is mutable. |
|
126 * mLayerCount counts the number of mask layers which have a reference to |
|
127 * MaskLayerImageEntry::mContainer; it is maintained by MaskLayerUserData, |
|
128 * which keeps a reference to the key. There will usually be mLayerCount + 1 |
|
129 * pointers to a key object (the +1 being from the hashtable entry), but this |
|
130 * invariant may be temporarily broken. |
|
131 */ |
|
132 struct MaskLayerImageKey |
|
133 { |
|
134 MaskLayerImageKey() |
|
135 : mLayerCount(0) |
|
136 , mRoundedClipRects() |
|
137 { |
|
138 MOZ_COUNT_CTOR(MaskLayerImageKey); |
|
139 } |
|
140 MaskLayerImageKey(const MaskLayerImageKey& aKey) |
|
141 : mLayerCount(aKey.mLayerCount) |
|
142 , mRoundedClipRects(aKey.mRoundedClipRects) |
|
143 { |
|
144 MOZ_COUNT_CTOR(MaskLayerImageKey); |
|
145 } |
|
146 |
|
147 ~MaskLayerImageKey() |
|
148 { |
|
149 MOZ_COUNT_DTOR(MaskLayerImageKey); |
|
150 } |
|
151 |
|
152 void AddRef() const { ++mLayerCount; } |
|
153 void Release() const |
|
154 { |
|
155 NS_ASSERTION(mLayerCount > 0, "Inconsistent layer count"); |
|
156 --mLayerCount; |
|
157 } |
|
158 |
|
159 PLDHashNumber Hash() const |
|
160 { |
|
161 PLDHashNumber hash = 0; |
|
162 |
|
163 for (uint32_t i = 0; i < mRoundedClipRects.Length(); ++i) { |
|
164 hash = AddToHash(hash, mRoundedClipRects[i].Hash()); |
|
165 } |
|
166 |
|
167 return hash; |
|
168 } |
|
169 |
|
170 bool operator==(const MaskLayerImageKey& aOther) const |
|
171 { |
|
172 return mRoundedClipRects == aOther.mRoundedClipRects; |
|
173 } |
|
174 |
|
175 mutable uint32_t mLayerCount; |
|
176 nsTArray<PixelRoundedRect> mRoundedClipRects; |
|
177 }; |
|
178 |
|
179 |
|
180 // Find an image container for aKey, returns nullptr if there is no suitable |
|
181 // cached image. If there is an image, then aKey is set to point at the stored |
|
182 // key for the image. |
|
183 ImageContainer* FindImageFor(const MaskLayerImageKey** aKey); |
|
184 |
|
185 // Add an image container with a key to the cache |
|
186 // The image container used will be set as the container in aKey and aKey |
|
187 // itself will be linked from this cache |
|
188 void PutImage(const MaskLayerImageKey* aKey, |
|
189 ImageContainer* aContainer); |
|
190 |
|
191 // Sweep the cache for old image containers that can be deleted |
|
192 void Sweep(); |
|
193 |
|
194 protected: |
|
195 |
|
196 class MaskLayerImageEntry : public PLDHashEntryHdr |
|
197 { |
|
198 public: |
|
199 typedef const MaskLayerImageKey& KeyType; |
|
200 typedef const MaskLayerImageKey* KeyTypePointer; |
|
201 |
|
202 MaskLayerImageEntry(KeyTypePointer aKey) : mKey(aKey) |
|
203 { |
|
204 MOZ_COUNT_CTOR(MaskLayerImageEntry); |
|
205 } |
|
206 MaskLayerImageEntry(const MaskLayerImageEntry& aOther) |
|
207 : mKey(aOther.mKey.get()) |
|
208 { |
|
209 NS_ERROR("ALLOW_MEMMOVE == true, should never be called"); |
|
210 } |
|
211 ~MaskLayerImageEntry() |
|
212 { |
|
213 MOZ_COUNT_DTOR(MaskLayerImageEntry); |
|
214 } |
|
215 |
|
216 // KeyEquals(): does this entry match this key? |
|
217 bool KeyEquals(KeyTypePointer aKey) const |
|
218 { |
|
219 return *mKey == *aKey; |
|
220 } |
|
221 |
|
222 // KeyToPointer(): Convert KeyType to KeyTypePointer |
|
223 static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } |
|
224 |
|
225 // HashKey(): calculate the hash number |
|
226 static PLDHashNumber HashKey(KeyTypePointer aKey) |
|
227 { |
|
228 return aKey->Hash(); |
|
229 } |
|
230 |
|
231 // ALLOW_MEMMOVE can we move this class with memmove(), or do we have |
|
232 // to use the copy constructor? |
|
233 enum { ALLOW_MEMMOVE = true }; |
|
234 |
|
235 bool operator==(const MaskLayerImageEntry& aOther) const |
|
236 { |
|
237 return KeyEquals(aOther.mKey); |
|
238 } |
|
239 |
|
240 nsAutoPtr<const MaskLayerImageKey> mKey; |
|
241 nsRefPtr<ImageContainer> mContainer; |
|
242 }; |
|
243 |
|
244 nsTHashtable<MaskLayerImageEntry> mMaskImageContainers; |
|
245 |
|
246 // helper funtion for Sweep(), called for each entry in the hashtable |
|
247 static PLDHashOperator SweepFunc(MaskLayerImageEntry* aEntry, void* aUserArg); |
|
248 }; |
|
249 |
|
250 } |
|
251 |
|
252 |
|
253 #endif |