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::SetInternal( 14 const nsIFrame* aFrame, UntypedDescriptor aProperty, 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::GetInternal( 63 const nsIFrame* aFrame, UntypedDescriptor aProperty, bool* aFoundResult) 64 { 65 NS_ASSERTION(aFrame, "Null frame?"); 66 NS_ASSERTION(aProperty, "Null property?"); 67 68 if (aFoundResult) { 69 *aFoundResult = false; 70 } 71 72 if (mLastFrame != aFrame) { 73 mLastFrame = aFrame; 74 mLastEntry = mEntries.GetEntry(mLastFrame); 75 } 76 Entry* entry = mLastEntry; 77 if (!entry) 78 return nullptr; 79 80 if (entry->mProp.mProperty == aProperty) { 81 if (aFoundResult) { 82 *aFoundResult = true; 83 } 84 return entry->mProp.mValue; 85 } 86 if (!entry->mProp.IsArray()) { 87 // There's just one property and it's not the one we want, bail 88 return nullptr; 89 } 90 91 nsTArray<PropertyValue>* array = entry->mProp.ToArray(); 92 nsTArray<PropertyValue>::index_type index = 93 array->IndexOf(aProperty, 0, PropertyComparator()); 94 if (index == nsTArray<PropertyValue>::NoIndex) 95 return nullptr; 96 97 if (aFoundResult) { 98 *aFoundResult = true; 99 } 100 101 return array->ElementAt(index).mValue; 102 } 103 104 void* 105 FramePropertyTable::RemoveInternal( 106 const nsIFrame* aFrame, UntypedDescriptor aProperty, bool* aFoundResult) 107 { 108 NS_ASSERTION(aFrame, "Null frame?"); 109 NS_ASSERTION(aProperty, "Null property?"); 110 111 if (aFoundResult) { 112 *aFoundResult = false; 113 } 114 115 if (mLastFrame != aFrame) { 116 mLastFrame = aFrame; 117 mLastEntry = mEntries.GetEntry(aFrame); 118 } 119 Entry* entry = mLastEntry; 120 if (!entry) 121 return nullptr; 122 123 if (entry->mProp.mProperty == aProperty) { 124 // There's only one entry and it's the one we want 125 void* value = entry->mProp.mValue; 126 127 // Here it's ok to use RemoveEntry() -- which may resize mEntries -- 128 // because we null mLastEntry at the same time. 129 mEntries.RemoveEntry(entry); 130 mLastEntry = nullptr; 131 if (aFoundResult) { 132 *aFoundResult = true; 133 } 134 return value; 135 } 136 if (!entry->mProp.IsArray()) { 137 // There's just one property and it's not the one we want, bail 138 return nullptr; 139 } 140 141 nsTArray<PropertyValue>* array = entry->mProp.ToArray(); 142 nsTArray<PropertyValue>::index_type index = 143 array->IndexOf(aProperty, 0, PropertyComparator()); 144 if (index == nsTArray<PropertyValue>::NoIndex) { 145 // No such property, bail 146 return nullptr; 147 } 148 149 if (aFoundResult) { 150 *aFoundResult = true; 151 } 152 153 void* result = array->ElementAt(index).mValue; 154 155 uint32_t last = array->Length() - 1; 156 array->ElementAt(index) = array->ElementAt(last); 157 array->RemoveElementAt(last); 158 159 if (last == 1) { 160 PropertyValue pv = array->ElementAt(0); 161 array->~nsTArray<PropertyValue>(); 162 entry->mProp = pv; 163 } 164 165 return result; 166 } 167 168 void 169 FramePropertyTable::DeleteInternal( 170 const nsIFrame* aFrame, UntypedDescriptor aProperty) 171 { 172 NS_ASSERTION(aFrame, "Null frame?"); 173 NS_ASSERTION(aProperty, "Null property?"); 174 175 bool found; 176 void* v = RemoveInternal(aFrame, aProperty, &found); 177 if (found) { 178 PropertyValue pv(aProperty, v); 179 pv.DestroyValueFor(aFrame); 180 } 181 } 182 183 /* static */ void 184 FramePropertyTable::DeleteAllForEntry(Entry* aEntry) 185 { 186 if (!aEntry->mProp.IsArray()) { 187 aEntry->mProp.DestroyValueFor(aEntry->GetKey()); 188 return; 189 } 190 191 nsTArray<PropertyValue>* array = aEntry->mProp.ToArray(); 192 for (uint32_t i = 0; i < array->Length(); ++i) { 193 array->ElementAt(i).DestroyValueFor(aEntry->GetKey()); 194 } 195 array->~nsTArray<PropertyValue>(); 196 } 197 198 void 199 FramePropertyTable::DeleteAllFor(const nsIFrame* aFrame) 200 { 201 NS_ASSERTION(aFrame, "Null frame?"); 202 203 Entry* entry = mEntries.GetEntry(aFrame); 204 if (!entry) 205 return; 206 207 if (mLastFrame == aFrame) { 208 // Flush cache. We assume DeleteAllForEntry will be called before 209 // a frame is destroyed. 210 mLastFrame = nullptr; 211 mLastEntry = nullptr; 212 } 213 214 DeleteAllForEntry(entry); 215 216 // mLastEntry points into mEntries, so we use RawRemoveEntry() which will not 217 // resize mEntries. 218 mEntries.RawRemoveEntry(entry); 219 } 220 221 void 222 FramePropertyTable::DeleteAll() 223 { 224 mLastFrame = nullptr; 225 mLastEntry = nullptr; 226 227 for (auto iter = mEntries.Iter(); !iter.Done(); iter.Next()) { 228 DeleteAllForEntry(iter.Get()); 229 } 230 mEntries.Clear(); 231 } 232 233 size_t 234 FramePropertyTable::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const 235 { 236 return mEntries.SizeOfExcludingThis(aMallocSizeOf); 237 } 238 239 } // namespace mozilla 240