summaryrefslogtreecommitdiffstats
path: root/layout/base/FramePropertyTable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/base/FramePropertyTable.cpp')
-rw-r--r--layout/base/FramePropertyTable.cpp239
1 files changed, 239 insertions, 0 deletions
diff --git a/layout/base/FramePropertyTable.cpp b/layout/base/FramePropertyTable.cpp
new file mode 100644
index 000000000..0fd9b1c37
--- /dev/null
+++ b/layout/base/FramePropertyTable.cpp
@@ -0,0 +1,239 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "FramePropertyTable.h"
+
+#include "mozilla/MemoryReporting.h"
+
+namespace mozilla {
+
+void
+FramePropertyTable::SetInternal(
+ const nsIFrame* aFrame, UntypedDescriptor aProperty, void* aValue)
+{
+ NS_ASSERTION(aFrame, "Null frame?");
+ NS_ASSERTION(aProperty, "Null property?");
+
+ if (mLastFrame != aFrame || !mLastEntry) {
+ mLastFrame = aFrame;
+ mLastEntry = mEntries.PutEntry(aFrame);
+ }
+ Entry* entry = mLastEntry;
+
+ if (!entry->mProp.IsArray()) {
+ if (!entry->mProp.mProperty) {
+ // Empty entry, so we can just store our property in the empty slot
+ entry->mProp.mProperty = aProperty;
+ entry->mProp.mValue = aValue;
+ return;
+ }
+ if (entry->mProp.mProperty == aProperty) {
+ // Just overwrite the current value
+ entry->mProp.DestroyValueFor(aFrame);
+ entry->mProp.mValue = aValue;
+ return;
+ }
+
+ // We need to expand the single current entry to an array
+ PropertyValue current = entry->mProp;
+ entry->mProp.mProperty = nullptr;
+ static_assert(sizeof(nsTArray<PropertyValue>) <= sizeof(void *),
+ "Property array must fit entirely within entry->mProp.mValue");
+ new (&entry->mProp.mValue) nsTArray<PropertyValue>(4);
+ entry->mProp.ToArray()->AppendElement(current);
+ }
+
+ nsTArray<PropertyValue>* array = entry->mProp.ToArray();
+ nsTArray<PropertyValue>::index_type index =
+ array->IndexOf(aProperty, 0, PropertyComparator());
+ if (index != nsTArray<PropertyValue>::NoIndex) {
+ PropertyValue* pv = &array->ElementAt(index);
+ pv->DestroyValueFor(aFrame);
+ pv->mValue = aValue;
+ return;
+ }
+
+ array->AppendElement(PropertyValue(aProperty, aValue));
+}
+
+void*
+FramePropertyTable::GetInternal(
+ const nsIFrame* aFrame, UntypedDescriptor aProperty, bool* aFoundResult)
+{
+ NS_ASSERTION(aFrame, "Null frame?");
+ NS_ASSERTION(aProperty, "Null property?");
+
+ if (aFoundResult) {
+ *aFoundResult = false;
+ }
+
+ if (mLastFrame != aFrame) {
+ mLastFrame = aFrame;
+ mLastEntry = mEntries.GetEntry(mLastFrame);
+ }
+ Entry* entry = mLastEntry;
+ if (!entry)
+ return nullptr;
+
+ if (entry->mProp.mProperty == aProperty) {
+ if (aFoundResult) {
+ *aFoundResult = true;
+ }
+ return entry->mProp.mValue;
+ }
+ if (!entry->mProp.IsArray()) {
+ // There's just one property and it's not the one we want, bail
+ return nullptr;
+ }
+
+ nsTArray<PropertyValue>* array = entry->mProp.ToArray();
+ nsTArray<PropertyValue>::index_type index =
+ array->IndexOf(aProperty, 0, PropertyComparator());
+ if (index == nsTArray<PropertyValue>::NoIndex)
+ return nullptr;
+
+ if (aFoundResult) {
+ *aFoundResult = true;
+ }
+
+ return array->ElementAt(index).mValue;
+}
+
+void*
+FramePropertyTable::RemoveInternal(
+ const nsIFrame* aFrame, UntypedDescriptor aProperty, bool* aFoundResult)
+{
+ NS_ASSERTION(aFrame, "Null frame?");
+ NS_ASSERTION(aProperty, "Null property?");
+
+ if (aFoundResult) {
+ *aFoundResult = false;
+ }
+
+ if (mLastFrame != aFrame) {
+ mLastFrame = aFrame;
+ mLastEntry = mEntries.GetEntry(aFrame);
+ }
+ Entry* entry = mLastEntry;
+ if (!entry)
+ return nullptr;
+
+ if (entry->mProp.mProperty == aProperty) {
+ // There's only one entry and it's the one we want
+ void* value = entry->mProp.mValue;
+
+ // Here it's ok to use RemoveEntry() -- which may resize mEntries --
+ // because we null mLastEntry at the same time.
+ mEntries.RemoveEntry(entry);
+ mLastEntry = nullptr;
+ if (aFoundResult) {
+ *aFoundResult = true;
+ }
+ return value;
+ }
+ if (!entry->mProp.IsArray()) {
+ // There's just one property and it's not the one we want, bail
+ return nullptr;
+ }
+
+ nsTArray<PropertyValue>* array = entry->mProp.ToArray();
+ nsTArray<PropertyValue>::index_type index =
+ array->IndexOf(aProperty, 0, PropertyComparator());
+ if (index == nsTArray<PropertyValue>::NoIndex) {
+ // No such property, bail
+ return nullptr;
+ }
+
+ if (aFoundResult) {
+ *aFoundResult = true;
+ }
+
+ void* result = array->ElementAt(index).mValue;
+
+ uint32_t last = array->Length() - 1;
+ array->ElementAt(index) = array->ElementAt(last);
+ array->RemoveElementAt(last);
+
+ if (last == 1) {
+ PropertyValue pv = array->ElementAt(0);
+ array->~nsTArray<PropertyValue>();
+ entry->mProp = pv;
+ }
+
+ return result;
+}
+
+void
+FramePropertyTable::DeleteInternal(
+ const nsIFrame* aFrame, UntypedDescriptor aProperty)
+{
+ NS_ASSERTION(aFrame, "Null frame?");
+ NS_ASSERTION(aProperty, "Null property?");
+
+ bool found;
+ void* v = RemoveInternal(aFrame, aProperty, &found);
+ if (found) {
+ PropertyValue pv(aProperty, v);
+ pv.DestroyValueFor(aFrame);
+ }
+}
+
+/* static */ void
+FramePropertyTable::DeleteAllForEntry(Entry* aEntry)
+{
+ if (!aEntry->mProp.IsArray()) {
+ aEntry->mProp.DestroyValueFor(aEntry->GetKey());
+ return;
+ }
+
+ nsTArray<PropertyValue>* array = aEntry->mProp.ToArray();
+ for (uint32_t i = 0; i < array->Length(); ++i) {
+ array->ElementAt(i).DestroyValueFor(aEntry->GetKey());
+ }
+ array->~nsTArray<PropertyValue>();
+}
+
+void
+FramePropertyTable::DeleteAllFor(const nsIFrame* aFrame)
+{
+ NS_ASSERTION(aFrame, "Null frame?");
+
+ Entry* entry = mEntries.GetEntry(aFrame);
+ if (!entry)
+ return;
+
+ if (mLastFrame == aFrame) {
+ // Flush cache. We assume DeleteAllForEntry will be called before
+ // a frame is destroyed.
+ mLastFrame = nullptr;
+ mLastEntry = nullptr;
+ }
+
+ DeleteAllForEntry(entry);
+
+ // mLastEntry points into mEntries, so we use RawRemoveEntry() which will not
+ // resize mEntries.
+ mEntries.RawRemoveEntry(entry);
+}
+
+void
+FramePropertyTable::DeleteAll()
+{
+ mLastFrame = nullptr;
+ mLastEntry = nullptr;
+
+ for (auto iter = mEntries.Iter(); !iter.Done(); iter.Next()) {
+ DeleteAllForEntry(iter.Get());
+ }
+ mEntries.Clear();
+}
+
+size_t
+FramePropertyTable::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+{
+ return mEntries.SizeOfExcludingThis(aMallocSizeOf);
+}
+
+} // namespace mozilla