michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "FramePropertyTable.h" michael@0: michael@0: #include "mozilla/MemoryReporting.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: void michael@0: FramePropertyTable::Set(nsIFrame* aFrame, const FramePropertyDescriptor* aProperty, michael@0: void* aValue) michael@0: { michael@0: NS_ASSERTION(aFrame, "Null frame?"); michael@0: NS_ASSERTION(aProperty, "Null property?"); michael@0: michael@0: if (mLastFrame != aFrame || !mLastEntry) { michael@0: mLastFrame = aFrame; michael@0: mLastEntry = mEntries.PutEntry(aFrame); michael@0: } michael@0: Entry* entry = mLastEntry; michael@0: michael@0: if (!entry->mProp.IsArray()) { michael@0: if (!entry->mProp.mProperty) { michael@0: // Empty entry, so we can just store our property in the empty slot michael@0: entry->mProp.mProperty = aProperty; michael@0: entry->mProp.mValue = aValue; michael@0: return; michael@0: } michael@0: if (entry->mProp.mProperty == aProperty) { michael@0: // Just overwrite the current value michael@0: entry->mProp.DestroyValueFor(aFrame); michael@0: entry->mProp.mValue = aValue; michael@0: return; michael@0: } michael@0: michael@0: // We need to expand the single current entry to an array michael@0: PropertyValue current = entry->mProp; michael@0: entry->mProp.mProperty = nullptr; michael@0: static_assert(sizeof(nsTArray) <= sizeof(void *), michael@0: "Property array must fit entirely within entry->mProp.mValue"); michael@0: new (&entry->mProp.mValue) nsTArray(4); michael@0: entry->mProp.ToArray()->AppendElement(current); michael@0: } michael@0: michael@0: nsTArray* array = entry->mProp.ToArray(); michael@0: nsTArray::index_type index = michael@0: array->IndexOf(aProperty, 0, PropertyComparator()); michael@0: if (index != nsTArray::NoIndex) { michael@0: PropertyValue* pv = &array->ElementAt(index); michael@0: pv->DestroyValueFor(aFrame); michael@0: pv->mValue = aValue; michael@0: return; michael@0: } michael@0: michael@0: array->AppendElement(PropertyValue(aProperty, aValue)); michael@0: } michael@0: michael@0: void* michael@0: FramePropertyTable::Get(const nsIFrame* aFrame, michael@0: const FramePropertyDescriptor* aProperty, michael@0: bool* aFoundResult) michael@0: { michael@0: NS_ASSERTION(aFrame, "Null frame?"); michael@0: NS_ASSERTION(aProperty, "Null property?"); michael@0: michael@0: if (aFoundResult) { michael@0: *aFoundResult = false; michael@0: } michael@0: michael@0: if (mLastFrame != aFrame) { michael@0: mLastFrame = const_cast(aFrame); michael@0: mLastEntry = mEntries.GetEntry(mLastFrame); michael@0: } michael@0: Entry* entry = mLastEntry; michael@0: if (!entry) michael@0: return nullptr; michael@0: michael@0: if (entry->mProp.mProperty == aProperty) { michael@0: if (aFoundResult) { michael@0: *aFoundResult = true; michael@0: } michael@0: return entry->mProp.mValue; michael@0: } michael@0: if (!entry->mProp.IsArray()) { michael@0: // There's just one property and it's not the one we want, bail michael@0: return nullptr; michael@0: } michael@0: michael@0: nsTArray* array = entry->mProp.ToArray(); michael@0: nsTArray::index_type index = michael@0: array->IndexOf(aProperty, 0, PropertyComparator()); michael@0: if (index == nsTArray::NoIndex) michael@0: return nullptr; michael@0: michael@0: if (aFoundResult) { michael@0: *aFoundResult = true; michael@0: } michael@0: michael@0: return array->ElementAt(index).mValue; michael@0: } michael@0: michael@0: void* michael@0: FramePropertyTable::Remove(nsIFrame* aFrame, const FramePropertyDescriptor* aProperty, michael@0: bool* aFoundResult) michael@0: { michael@0: NS_ASSERTION(aFrame, "Null frame?"); michael@0: NS_ASSERTION(aProperty, "Null property?"); michael@0: michael@0: if (aFoundResult) { michael@0: *aFoundResult = false; michael@0: } michael@0: michael@0: if (mLastFrame != aFrame) { michael@0: mLastFrame = aFrame; michael@0: mLastEntry = mEntries.GetEntry(aFrame); michael@0: } michael@0: Entry* entry = mLastEntry; michael@0: if (!entry) michael@0: return nullptr; michael@0: michael@0: if (entry->mProp.mProperty == aProperty) { michael@0: // There's only one entry and it's the one we want michael@0: void* value = entry->mProp.mValue; michael@0: mEntries.RawRemoveEntry(entry); michael@0: mLastEntry = nullptr; michael@0: if (aFoundResult) { michael@0: *aFoundResult = true; michael@0: } michael@0: return value; michael@0: } michael@0: if (!entry->mProp.IsArray()) { michael@0: // There's just one property and it's not the one we want, bail michael@0: return nullptr; michael@0: } michael@0: michael@0: nsTArray* array = entry->mProp.ToArray(); michael@0: nsTArray::index_type index = michael@0: array->IndexOf(aProperty, 0, PropertyComparator()); michael@0: if (index == nsTArray::NoIndex) { michael@0: // No such property, bail michael@0: return nullptr; michael@0: } michael@0: michael@0: if (aFoundResult) { michael@0: *aFoundResult = true; michael@0: } michael@0: michael@0: void* result = array->ElementAt(index).mValue; michael@0: michael@0: uint32_t last = array->Length() - 1; michael@0: array->ElementAt(index) = array->ElementAt(last); michael@0: array->RemoveElementAt(last); michael@0: michael@0: if (last == 1) { michael@0: PropertyValue pv = array->ElementAt(0); michael@0: array->~nsTArray(); michael@0: entry->mProp = pv; michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: void michael@0: FramePropertyTable::Delete(nsIFrame* aFrame, const FramePropertyDescriptor* aProperty) michael@0: { michael@0: NS_ASSERTION(aFrame, "Null frame?"); michael@0: NS_ASSERTION(aProperty, "Null property?"); michael@0: michael@0: bool found; michael@0: void* v = Remove(aFrame, aProperty, &found); michael@0: if (found) { michael@0: PropertyValue pv(aProperty, v); michael@0: pv.DestroyValueFor(aFrame); michael@0: } michael@0: } michael@0: michael@0: /* static */ void michael@0: FramePropertyTable::DeleteAllForEntry(Entry* aEntry) michael@0: { michael@0: if (!aEntry->mProp.IsArray()) { michael@0: aEntry->mProp.DestroyValueFor(aEntry->GetKey()); michael@0: return; michael@0: } michael@0: michael@0: nsTArray* array = aEntry->mProp.ToArray(); michael@0: for (uint32_t i = 0; i < array->Length(); ++i) { michael@0: array->ElementAt(i).DestroyValueFor(aEntry->GetKey()); michael@0: } michael@0: array->~nsTArray(); michael@0: } michael@0: michael@0: void michael@0: FramePropertyTable::DeleteAllFor(nsIFrame* aFrame) michael@0: { michael@0: NS_ASSERTION(aFrame, "Null frame?"); michael@0: michael@0: Entry* entry = mEntries.GetEntry(aFrame); michael@0: if (!entry) michael@0: return; michael@0: michael@0: if (mLastFrame == aFrame) { michael@0: // Flush cache. We assume DeleteAllForEntry will be called before michael@0: // a frame is destroyed. michael@0: mLastFrame = nullptr; michael@0: mLastEntry = nullptr; michael@0: } michael@0: michael@0: DeleteAllForEntry(entry); michael@0: mEntries.RawRemoveEntry(entry); michael@0: } michael@0: michael@0: /* static */ PLDHashOperator michael@0: FramePropertyTable::DeleteEnumerator(Entry* aEntry, void* aArg) michael@0: { michael@0: DeleteAllForEntry(aEntry); michael@0: return PL_DHASH_REMOVE; michael@0: } michael@0: michael@0: void michael@0: FramePropertyTable::DeleteAll() michael@0: { michael@0: mLastFrame = nullptr; michael@0: mLastEntry = nullptr; michael@0: michael@0: mEntries.EnumerateEntries(DeleteEnumerator, nullptr); michael@0: } michael@0: michael@0: size_t michael@0: FramePropertyTable::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const michael@0: { michael@0: return mEntries.SizeOfExcludingThis(SizeOfPropertyTableEntryExcludingThis, michael@0: aMallocSizeOf); michael@0: } michael@0: michael@0: /* static */ size_t michael@0: FramePropertyTable::SizeOfPropertyTableEntryExcludingThis(Entry* aEntry, michael@0: mozilla::MallocSizeOf aMallocSizeOf, void *) michael@0: { michael@0: return aEntry->mProp.SizeOfExcludingThis(aMallocSizeOf); michael@0: } michael@0: michael@0: }