|
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 #include "FramePropertyTable.h" |
|
7 |
|
8 #include "mozilla/MemoryReporting.h" |
|
9 |
|
10 namespace mozilla { |
|
11 |
|
12 void |
|
13 FramePropertyTable::Set(nsIFrame* aFrame, const FramePropertyDescriptor* aProperty, |
|
14 void* aValue) |
|
15 { |
|
16 NS_ASSERTION(aFrame, "Null frame?"); |
|
17 NS_ASSERTION(aProperty, "Null property?"); |
|
18 |
|
19 if (mLastFrame != aFrame || !mLastEntry) { |
|
20 mLastFrame = aFrame; |
|
21 mLastEntry = mEntries.PutEntry(aFrame); |
|
22 } |
|
23 Entry* entry = mLastEntry; |
|
24 |
|
25 if (!entry->mProp.IsArray()) { |
|
26 if (!entry->mProp.mProperty) { |
|
27 // Empty entry, so we can just store our property in the empty slot |
|
28 entry->mProp.mProperty = aProperty; |
|
29 entry->mProp.mValue = aValue; |
|
30 return; |
|
31 } |
|
32 if (entry->mProp.mProperty == aProperty) { |
|
33 // Just overwrite the current value |
|
34 entry->mProp.DestroyValueFor(aFrame); |
|
35 entry->mProp.mValue = aValue; |
|
36 return; |
|
37 } |
|
38 |
|
39 // We need to expand the single current entry to an array |
|
40 PropertyValue current = entry->mProp; |
|
41 entry->mProp.mProperty = nullptr; |
|
42 static_assert(sizeof(nsTArray<PropertyValue>) <= sizeof(void *), |
|
43 "Property array must fit entirely within entry->mProp.mValue"); |
|
44 new (&entry->mProp.mValue) nsTArray<PropertyValue>(4); |
|
45 entry->mProp.ToArray()->AppendElement(current); |
|
46 } |
|
47 |
|
48 nsTArray<PropertyValue>* array = entry->mProp.ToArray(); |
|
49 nsTArray<PropertyValue>::index_type index = |
|
50 array->IndexOf(aProperty, 0, PropertyComparator()); |
|
51 if (index != nsTArray<PropertyValue>::NoIndex) { |
|
52 PropertyValue* pv = &array->ElementAt(index); |
|
53 pv->DestroyValueFor(aFrame); |
|
54 pv->mValue = aValue; |
|
55 return; |
|
56 } |
|
57 |
|
58 array->AppendElement(PropertyValue(aProperty, aValue)); |
|
59 } |
|
60 |
|
61 void* |
|
62 FramePropertyTable::Get(const nsIFrame* aFrame, |
|
63 const FramePropertyDescriptor* aProperty, |
|
64 bool* aFoundResult) |
|
65 { |
|
66 NS_ASSERTION(aFrame, "Null frame?"); |
|
67 NS_ASSERTION(aProperty, "Null property?"); |
|
68 |
|
69 if (aFoundResult) { |
|
70 *aFoundResult = false; |
|
71 } |
|
72 |
|
73 if (mLastFrame != aFrame) { |
|
74 mLastFrame = const_cast<nsIFrame*>(aFrame); |
|
75 mLastEntry = mEntries.GetEntry(mLastFrame); |
|
76 } |
|
77 Entry* entry = mLastEntry; |
|
78 if (!entry) |
|
79 return nullptr; |
|
80 |
|
81 if (entry->mProp.mProperty == aProperty) { |
|
82 if (aFoundResult) { |
|
83 *aFoundResult = true; |
|
84 } |
|
85 return entry->mProp.mValue; |
|
86 } |
|
87 if (!entry->mProp.IsArray()) { |
|
88 // There's just one property and it's not the one we want, bail |
|
89 return nullptr; |
|
90 } |
|
91 |
|
92 nsTArray<PropertyValue>* array = entry->mProp.ToArray(); |
|
93 nsTArray<PropertyValue>::index_type index = |
|
94 array->IndexOf(aProperty, 0, PropertyComparator()); |
|
95 if (index == nsTArray<PropertyValue>::NoIndex) |
|
96 return nullptr; |
|
97 |
|
98 if (aFoundResult) { |
|
99 *aFoundResult = true; |
|
100 } |
|
101 |
|
102 return array->ElementAt(index).mValue; |
|
103 } |
|
104 |
|
105 void* |
|
106 FramePropertyTable::Remove(nsIFrame* aFrame, const FramePropertyDescriptor* aProperty, |
|
107 bool* aFoundResult) |
|
108 { |
|
109 NS_ASSERTION(aFrame, "Null frame?"); |
|
110 NS_ASSERTION(aProperty, "Null property?"); |
|
111 |
|
112 if (aFoundResult) { |
|
113 *aFoundResult = false; |
|
114 } |
|
115 |
|
116 if (mLastFrame != aFrame) { |
|
117 mLastFrame = aFrame; |
|
118 mLastEntry = mEntries.GetEntry(aFrame); |
|
119 } |
|
120 Entry* entry = mLastEntry; |
|
121 if (!entry) |
|
122 return nullptr; |
|
123 |
|
124 if (entry->mProp.mProperty == aProperty) { |
|
125 // There's only one entry and it's the one we want |
|
126 void* value = entry->mProp.mValue; |
|
127 mEntries.RawRemoveEntry(entry); |
|
128 mLastEntry = nullptr; |
|
129 if (aFoundResult) { |
|
130 *aFoundResult = true; |
|
131 } |
|
132 return value; |
|
133 } |
|
134 if (!entry->mProp.IsArray()) { |
|
135 // There's just one property and it's not the one we want, bail |
|
136 return nullptr; |
|
137 } |
|
138 |
|
139 nsTArray<PropertyValue>* array = entry->mProp.ToArray(); |
|
140 nsTArray<PropertyValue>::index_type index = |
|
141 array->IndexOf(aProperty, 0, PropertyComparator()); |
|
142 if (index == nsTArray<PropertyValue>::NoIndex) { |
|
143 // No such property, bail |
|
144 return nullptr; |
|
145 } |
|
146 |
|
147 if (aFoundResult) { |
|
148 *aFoundResult = true; |
|
149 } |
|
150 |
|
151 void* result = array->ElementAt(index).mValue; |
|
152 |
|
153 uint32_t last = array->Length() - 1; |
|
154 array->ElementAt(index) = array->ElementAt(last); |
|
155 array->RemoveElementAt(last); |
|
156 |
|
157 if (last == 1) { |
|
158 PropertyValue pv = array->ElementAt(0); |
|
159 array->~nsTArray<PropertyValue>(); |
|
160 entry->mProp = pv; |
|
161 } |
|
162 |
|
163 return result; |
|
164 } |
|
165 |
|
166 void |
|
167 FramePropertyTable::Delete(nsIFrame* aFrame, const FramePropertyDescriptor* aProperty) |
|
168 { |
|
169 NS_ASSERTION(aFrame, "Null frame?"); |
|
170 NS_ASSERTION(aProperty, "Null property?"); |
|
171 |
|
172 bool found; |
|
173 void* v = Remove(aFrame, aProperty, &found); |
|
174 if (found) { |
|
175 PropertyValue pv(aProperty, v); |
|
176 pv.DestroyValueFor(aFrame); |
|
177 } |
|
178 } |
|
179 |
|
180 /* static */ void |
|
181 FramePropertyTable::DeleteAllForEntry(Entry* aEntry) |
|
182 { |
|
183 if (!aEntry->mProp.IsArray()) { |
|
184 aEntry->mProp.DestroyValueFor(aEntry->GetKey()); |
|
185 return; |
|
186 } |
|
187 |
|
188 nsTArray<PropertyValue>* array = aEntry->mProp.ToArray(); |
|
189 for (uint32_t i = 0; i < array->Length(); ++i) { |
|
190 array->ElementAt(i).DestroyValueFor(aEntry->GetKey()); |
|
191 } |
|
192 array->~nsTArray<PropertyValue>(); |
|
193 } |
|
194 |
|
195 void |
|
196 FramePropertyTable::DeleteAllFor(nsIFrame* aFrame) |
|
197 { |
|
198 NS_ASSERTION(aFrame, "Null frame?"); |
|
199 |
|
200 Entry* entry = mEntries.GetEntry(aFrame); |
|
201 if (!entry) |
|
202 return; |
|
203 |
|
204 if (mLastFrame == aFrame) { |
|
205 // Flush cache. We assume DeleteAllForEntry will be called before |
|
206 // a frame is destroyed. |
|
207 mLastFrame = nullptr; |
|
208 mLastEntry = nullptr; |
|
209 } |
|
210 |
|
211 DeleteAllForEntry(entry); |
|
212 mEntries.RawRemoveEntry(entry); |
|
213 } |
|
214 |
|
215 /* static */ PLDHashOperator |
|
216 FramePropertyTable::DeleteEnumerator(Entry* aEntry, void* aArg) |
|
217 { |
|
218 DeleteAllForEntry(aEntry); |
|
219 return PL_DHASH_REMOVE; |
|
220 } |
|
221 |
|
222 void |
|
223 FramePropertyTable::DeleteAll() |
|
224 { |
|
225 mLastFrame = nullptr; |
|
226 mLastEntry = nullptr; |
|
227 |
|
228 mEntries.EnumerateEntries(DeleteEnumerator, nullptr); |
|
229 } |
|
230 |
|
231 size_t |
|
232 FramePropertyTable::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const |
|
233 { |
|
234 return mEntries.SizeOfExcludingThis(SizeOfPropertyTableEntryExcludingThis, |
|
235 aMallocSizeOf); |
|
236 } |
|
237 |
|
238 /* static */ size_t |
|
239 FramePropertyTable::SizeOfPropertyTableEntryExcludingThis(Entry* aEntry, |
|
240 mozilla::MallocSizeOf aMallocSizeOf, void *) |
|
241 { |
|
242 return aEntry->mProp.SizeOfExcludingThis(aMallocSizeOf); |
|
243 } |
|
244 |
|
245 } |