|
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 FRAMEPROPERTYTABLE_H_ |
|
7 #define FRAMEPROPERTYTABLE_H_ |
|
8 |
|
9 #include "mozilla/MemoryReporting.h" |
|
10 #include "nsTArray.h" |
|
11 #include "nsTHashtable.h" |
|
12 #include "nsHashKeys.h" |
|
13 |
|
14 class nsIFrame; |
|
15 |
|
16 namespace mozilla { |
|
17 |
|
18 struct FramePropertyDescriptor; |
|
19 |
|
20 typedef void (*FramePropertyDestructor)(void* aPropertyValue); |
|
21 typedef void (*FramePropertyDestructorWithFrame)(nsIFrame* aFrame, |
|
22 void* aPropertyValue); |
|
23 |
|
24 /** |
|
25 * A pointer to a FramePropertyDescriptor serves as a unique property ID. |
|
26 * The FramePropertyDescriptor stores metadata about the property. |
|
27 * Currently the only metadata is a destructor function. The destructor |
|
28 * function is called on property values when they are overwritten or |
|
29 * deleted. |
|
30 * |
|
31 * To use this class, declare a global (i.e., file, class or function-scope |
|
32 * static member) FramePropertyDescriptor and pass its address as |
|
33 * aProperty in the FramePropertyTable methods. |
|
34 */ |
|
35 struct FramePropertyDescriptor { |
|
36 /** |
|
37 * mDestructor will be called if it's non-null. |
|
38 */ |
|
39 FramePropertyDestructor mDestructor; |
|
40 /** |
|
41 * mDestructorWithFrame will be called if it's non-null and mDestructor |
|
42 * is null. WARNING: The frame passed to mDestructorWithFrame may |
|
43 * be a dangling frame pointer, if this is being called during |
|
44 * presshell teardown. Do not use it except to compare against |
|
45 * other frame pointers. No frame will have been allocated with |
|
46 * the same address yet. |
|
47 */ |
|
48 FramePropertyDestructorWithFrame mDestructorWithFrame; |
|
49 /** |
|
50 * mDestructor and mDestructorWithFrame may both be null, in which case |
|
51 * no value destruction is a no-op. |
|
52 */ |
|
53 }; |
|
54 |
|
55 /** |
|
56 * The FramePropertyTable is optimized for storing 0 or 1 properties on |
|
57 * a given frame. Storing very large numbers of properties on a single |
|
58 * frame will not be efficient. |
|
59 * |
|
60 * Property values are passed as void* but do not actually have to be |
|
61 * valid pointers. You can use NS_INT32_TO_PTR/NS_PTR_TO_INT32 to |
|
62 * store int32_t values. Null/zero values can be stored and retrieved. |
|
63 * Of course, the destructor function (if any) must handle such values |
|
64 * correctly. |
|
65 */ |
|
66 class FramePropertyTable { |
|
67 public: |
|
68 FramePropertyTable() : mLastFrame(nullptr), mLastEntry(nullptr) |
|
69 { |
|
70 } |
|
71 ~FramePropertyTable() |
|
72 { |
|
73 DeleteAll(); |
|
74 } |
|
75 |
|
76 /** |
|
77 * Set a property value on a frame. This requires one hashtable |
|
78 * lookup (using the frame as the key) and a linear search through |
|
79 * the properties of that frame. Any existing value for the property |
|
80 * is destroyed. |
|
81 */ |
|
82 void Set(nsIFrame* aFrame, const FramePropertyDescriptor* aProperty, |
|
83 void* aValue); |
|
84 /** |
|
85 * Get a property value for a frame. This requires one hashtable |
|
86 * lookup (using the frame as the key) and a linear search through |
|
87 * the properties of that frame. If the frame has no such property, |
|
88 * returns null. |
|
89 * @param aFoundResult if non-null, receives a value 'true' iff |
|
90 * the frame has a value for the property. This lets callers |
|
91 * disambiguate a null result, which can mean 'no such property' or |
|
92 * 'property value is null'. |
|
93 */ |
|
94 void* Get(const nsIFrame* aFrame, const FramePropertyDescriptor* aProperty, |
|
95 bool* aFoundResult = nullptr); |
|
96 /** |
|
97 * Remove a property value for a frame. This requires one hashtable |
|
98 * lookup (using the frame as the key) and a linear search through |
|
99 * the properties of that frame. The old property value is returned |
|
100 * (and not destroyed). If the frame has no such property, |
|
101 * returns null. |
|
102 * @param aFoundResult if non-null, receives a value 'true' iff |
|
103 * the frame had a value for the property. This lets callers |
|
104 * disambiguate a null result, which can mean 'no such property' or |
|
105 * 'property value is null'. |
|
106 */ |
|
107 void* Remove(nsIFrame* aFrame, const FramePropertyDescriptor* aProperty, |
|
108 bool* aFoundResult = nullptr); |
|
109 /** |
|
110 * Remove and destroy a property value for a frame. This requires one |
|
111 * hashtable lookup (using the frame as the key) and a linear search |
|
112 * through the properties of that frame. If the frame has no such |
|
113 * property, nothing happens. |
|
114 */ |
|
115 void Delete(nsIFrame* aFrame, const FramePropertyDescriptor* aProperty); |
|
116 /** |
|
117 * Remove and destroy all property values for a frame. This requires one |
|
118 * hashtable lookup (using the frame as the key). |
|
119 */ |
|
120 void DeleteAllFor(nsIFrame* aFrame); |
|
121 /** |
|
122 * Remove and destroy all property values for all frames. |
|
123 */ |
|
124 void DeleteAll(); |
|
125 |
|
126 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; |
|
127 |
|
128 protected: |
|
129 /** |
|
130 * Stores a property descriptor/value pair. It can also be used to |
|
131 * store an nsTArray of PropertyValues. |
|
132 */ |
|
133 struct PropertyValue { |
|
134 PropertyValue() : mProperty(nullptr), mValue(nullptr) {} |
|
135 PropertyValue(const FramePropertyDescriptor* aProperty, void* aValue) |
|
136 : mProperty(aProperty), mValue(aValue) {} |
|
137 |
|
138 bool IsArray() { return !mProperty && mValue; } |
|
139 nsTArray<PropertyValue>* ToArray() |
|
140 { |
|
141 NS_ASSERTION(IsArray(), "Must be array"); |
|
142 return reinterpret_cast<nsTArray<PropertyValue>*>(&mValue); |
|
143 } |
|
144 |
|
145 void DestroyValueFor(nsIFrame* aFrame) { |
|
146 if (mProperty->mDestructor) { |
|
147 mProperty->mDestructor(mValue); |
|
148 } else if (mProperty->mDestructorWithFrame) { |
|
149 mProperty->mDestructorWithFrame(aFrame, mValue); |
|
150 } |
|
151 } |
|
152 |
|
153 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) { |
|
154 size_t n = 0; |
|
155 // We don't need to measure mProperty because it always points to static |
|
156 // memory. As for mValue: if it's a single value we can't measure it, |
|
157 // because the type is opaque; if it's an array, we measure the array |
|
158 // storage, but we can't measure the individual values, again because |
|
159 // their types are opaque. |
|
160 if (IsArray()) { |
|
161 nsTArray<PropertyValue>* array = ToArray(); |
|
162 n += array->SizeOfExcludingThis(aMallocSizeOf); |
|
163 } |
|
164 return n; |
|
165 } |
|
166 |
|
167 const FramePropertyDescriptor* mProperty; |
|
168 void* mValue; |
|
169 }; |
|
170 |
|
171 /** |
|
172 * Used with an array of PropertyValues to allow lookups that compare |
|
173 * only on the FramePropertyDescriptor. |
|
174 */ |
|
175 class PropertyComparator { |
|
176 public: |
|
177 bool Equals(const PropertyValue& a, const PropertyValue& b) const { |
|
178 return a.mProperty == b.mProperty; |
|
179 } |
|
180 bool Equals(const FramePropertyDescriptor* a, const PropertyValue& b) const { |
|
181 return a == b.mProperty; |
|
182 } |
|
183 bool Equals(const PropertyValue& a, const FramePropertyDescriptor* b) const { |
|
184 return a.mProperty == b; |
|
185 } |
|
186 }; |
|
187 |
|
188 /** |
|
189 * Our hashtable entry. The key is an nsIFrame*, the value is a |
|
190 * PropertyValue representing one or more property/value pairs. |
|
191 */ |
|
192 class Entry : public nsPtrHashKey<nsIFrame> |
|
193 { |
|
194 public: |
|
195 Entry(KeyTypePointer aKey) : nsPtrHashKey<nsIFrame>(aKey) {} |
|
196 Entry(const Entry &toCopy) : |
|
197 nsPtrHashKey<nsIFrame>(toCopy), mProp(toCopy.mProp) {} |
|
198 |
|
199 PropertyValue mProp; |
|
200 }; |
|
201 |
|
202 static void DeleteAllForEntry(Entry* aEntry); |
|
203 static PLDHashOperator DeleteEnumerator(Entry* aEntry, void* aArg); |
|
204 |
|
205 static size_t SizeOfPropertyTableEntryExcludingThis(Entry* aEntry, |
|
206 mozilla::MallocSizeOf aMallocSizeOf, void *); |
|
207 |
|
208 nsTHashtable<Entry> mEntries; |
|
209 nsIFrame* mLastFrame; |
|
210 Entry* mLastEntry; |
|
211 }; |
|
212 |
|
213 /** |
|
214 * This class encapsulates the properties of a frame. |
|
215 */ |
|
216 class FrameProperties { |
|
217 public: |
|
218 FrameProperties(FramePropertyTable* aTable, nsIFrame* aFrame) |
|
219 : mTable(aTable), mFrame(aFrame) {} |
|
220 FrameProperties(FramePropertyTable* aTable, const nsIFrame* aFrame) |
|
221 : mTable(aTable), mFrame(const_cast<nsIFrame*>(aFrame)) {} |
|
222 |
|
223 void Set(const FramePropertyDescriptor* aProperty, void* aValue) const |
|
224 { |
|
225 mTable->Set(mFrame, aProperty, aValue); |
|
226 } |
|
227 void* Get(const FramePropertyDescriptor* aProperty, |
|
228 bool* aFoundResult = nullptr) const |
|
229 { |
|
230 return mTable->Get(mFrame, aProperty, aFoundResult); |
|
231 } |
|
232 void* Remove(const FramePropertyDescriptor* aProperty, |
|
233 bool* aFoundResult = nullptr) const |
|
234 { |
|
235 return mTable->Remove(mFrame, aProperty, aFoundResult); |
|
236 } |
|
237 void Delete(const FramePropertyDescriptor* aProperty) |
|
238 { |
|
239 mTable->Delete(mFrame, aProperty); |
|
240 } |
|
241 |
|
242 private: |
|
243 FramePropertyTable* mTable; |
|
244 nsIFrame* mFrame; |
|
245 }; |
|
246 |
|
247 } |
|
248 |
|
249 #endif /* FRAMEPROPERTYTABLE_H_ */ |