From 00812e30dfa70f9b1a752cf0d09de00f6d401c85 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Wed, 26 Jun 2019 01:51:45 +0300 Subject: Attach FrameProperties to each frame instead of using a shared hashtable Dispense the shared hashtable and instead attach the frame property list directly to nsIFrame. --- layout/base/ActiveLayerTracker.cpp | 15 +- layout/base/FrameLayerBuilder.cpp | 32 ++- layout/base/FrameProperties.h | 440 +++++++++++++++++++++++++++++++++ layout/base/FramePropertyTable.cpp | 239 ------------------ layout/base/FramePropertyTable.h | 442 ---------------------------------- layout/base/OverflowChangedTracker.h | 4 +- layout/base/RestyleManager.cpp | 10 +- layout/base/RestyleManagerBase.cpp | 88 ++++--- layout/base/RestyleManagerBase.h | 13 +- layout/base/moz.build | 3 +- layout/base/nsBidiPresUtils.cpp | 5 +- layout/base/nsCSSFrameConstructor.cpp | 23 +- layout/base/nsCSSRendering.cpp | 10 +- layout/base/nsDisplayList.cpp | 8 +- layout/base/nsDisplayList.h | 2 +- layout/base/nsIPresShell.h | 11 +- layout/base/nsLayoutUtils.cpp | 16 +- layout/base/nsPresContext.cpp | 3 +- layout/base/nsPresContext.h | 11 - layout/base/nsPresShell.cpp | 35 ++- layout/base/nsPresShell.h | 11 +- 21 files changed, 590 insertions(+), 831 deletions(-) create mode 100644 layout/base/FrameProperties.h delete mode 100644 layout/base/FramePropertyTable.cpp delete mode 100644 layout/base/FramePropertyTable.h (limited to 'layout/base') diff --git a/layout/base/ActiveLayerTracker.cpp b/layout/base/ActiveLayerTracker.cpp index 4f60f82d7..ecee4897a 100644 --- a/layout/base/ActiveLayerTracker.cpp +++ b/layout/base/ActiveLayerTracker.cpp @@ -178,7 +178,7 @@ LayerActivityTracker::NotifyExpired(LayerActivity* aObject) f->SchedulePaint(); } f->RemoveStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY); - f->Properties().Delete(LayerActivityProperty()); + f->DeleteProperty(LayerActivityProperty()); } else { c->DeleteProperty(nsGkAtoms::LayerActivity); } @@ -190,15 +190,13 @@ GetLayerActivity(nsIFrame* aFrame) if (!aFrame->HasAnyStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY)) { return nullptr; } - FrameProperties properties = aFrame->Properties(); - return properties.Get(LayerActivityProperty()); + return aFrame->GetProperty(LayerActivityProperty()); } static LayerActivity* GetLayerActivityForUpdate(nsIFrame* aFrame) { - FrameProperties properties = aFrame->Properties(); - LayerActivity* layerActivity = properties.Get(LayerActivityProperty()); + LayerActivity* layerActivity = aFrame->GetProperty(LayerActivityProperty()); if (layerActivity) { gLayerActivityTracker->MarkUsed(layerActivity); } else { @@ -208,7 +206,7 @@ GetLayerActivityForUpdate(nsIFrame* aFrame) layerActivity = new LayerActivity(aFrame); gLayerActivityTracker->AddObject(layerActivity); aFrame->AddStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY); - properties.Set(LayerActivityProperty(), layerActivity); + aFrame->SetProperty(LayerActivityProperty(), layerActivity); } return layerActivity; } @@ -225,8 +223,7 @@ ActiveLayerTracker::TransferActivityToContent(nsIFrame* aFrame, nsIContent* aCon if (!aFrame->HasAnyStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY)) { return; } - FrameProperties properties = aFrame->Properties(); - LayerActivity* layerActivity = properties.Remove(LayerActivityProperty()); + LayerActivity* layerActivity = aFrame->RemoveProperty(LayerActivityProperty()); aFrame->RemoveStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY); if (!layerActivity) { return; @@ -248,7 +245,7 @@ ActiveLayerTracker::TransferActivityToFrame(nsIContent* aContent, nsIFrame* aFra layerActivity->mContent = nullptr; layerActivity->mFrame = aFrame; aFrame->AddStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY); - aFrame->Properties().Set(LayerActivityProperty(), layerActivity); + aFrame->SetProperty(LayerActivityProperty(), layerActivity); } static void diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 9aaa28fb5..e87d9dc09 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -165,10 +165,10 @@ FrameLayerBuilder::DisplayItemData::AddFrame(nsIFrame* aFrame) mFrameList.AppendElement(aFrame); nsTArray* array = - aFrame->Properties().Get(FrameLayerBuilder::LayerManagerDataProperty()); + aFrame->GetProperty(FrameLayerBuilder::LayerManagerDataProperty()); if (!array) { array = new nsTArray(); - aFrame->Properties().Set(FrameLayerBuilder::LayerManagerDataProperty(), array); + aFrame->SetProperty(FrameLayerBuilder::LayerManagerDataProperty(), array); } array->AppendElement(this); } @@ -181,7 +181,7 @@ FrameLayerBuilder::DisplayItemData::RemoveFrame(nsIFrame* aFrame) MOZ_RELEASE_ASSERT(result, "Can't remove a frame that wasn't added!"); nsTArray* array = - aFrame->Properties().Get(FrameLayerBuilder::LayerManagerDataProperty()); + aFrame->GetProperty(FrameLayerBuilder::LayerManagerDataProperty()); MOZ_RELEASE_ASSERT(array, "Must be already stored on the frame!"); array->RemoveElement(this); } @@ -268,7 +268,7 @@ FrameLayerBuilder::DisplayItemData::~DisplayItemData() continue; } nsTArray *array = - reinterpret_cast*>(frame->Properties().Get(LayerManagerDataProperty())); + reinterpret_cast*>(frame->GetProperty(LayerManagerDataProperty())); array->RemoveElement(this); } @@ -390,8 +390,7 @@ public: /* static */ void FrameLayerBuilder::DestroyDisplayItemDataFor(nsIFrame* aFrame) { - FrameProperties props = aFrame->Properties(); - props.Delete(LayerManagerDataProperty()); + aFrame->DeleteProperty(LayerManagerDataProperty()); } struct AssignedDisplayItem @@ -1823,7 +1822,7 @@ FrameLayerBuilder::DisplayItemData* FrameLayerBuilder::GetDisplayItemData(nsIFrame* aFrame, uint32_t aKey) { const nsTArray* array = - aFrame->Properties().Get(LayerManagerDataProperty()); + aFrame->GetProperty(LayerManagerDataProperty()); if (array) { for (uint32_t i = 0; i < array->Length(); i++) { DisplayItemData* item = AssertDisplayItemData(array->ElementAt(i)); @@ -2052,7 +2051,7 @@ FrameLayerBuilder::GetDisplayItemDataForManager(nsDisplayItem* aItem, LayerManager* aManager) { const nsTArray* array = - aItem->Frame()->Properties().Get(LayerManagerDataProperty()); + aItem->Frame()->GetProperty(LayerManagerDataProperty()); if (array) { for (uint32_t i = 0; i < array->Length(); i++) { DisplayItemData* item = AssertDisplayItemData(array->ElementAt(i)); @@ -2069,7 +2068,7 @@ bool FrameLayerBuilder::HasRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey) { const nsTArray* array = - aFrame->Properties().Get(LayerManagerDataProperty()); + aFrame->GetProperty(LayerManagerDataProperty()); if (array) { for (uint32_t i = 0; i < array->Length(); i++) { if (AssertDisplayItemData(array->ElementAt(i))->mDisplayItemKey == aDisplayItemKey) { @@ -2084,7 +2083,7 @@ void FrameLayerBuilder::IterateRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallback aCallback) { const nsTArray* array = - aFrame->Properties().Get(LayerManagerDataProperty()); + aFrame->GetProperty(LayerManagerDataProperty()); if (!array) { return; } @@ -2151,7 +2150,7 @@ FrameLayerBuilder::ClearCachedGeometry(nsDisplayItem* aItem) FrameLayerBuilder::GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey) { const nsTArray* array = - aFrame->Properties().Get(LayerManagerDataProperty()); + aFrame->GetProperty(LayerManagerDataProperty()); if (!array) { return nullptr; @@ -2171,7 +2170,7 @@ FrameLayerBuilder::GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKe FrameLayerBuilder::GetDebugSingleOldPaintedLayerForFrame(nsIFrame* aFrame) { const nsTArray* array = - aFrame->Properties().Get(LayerManagerDataProperty()); + aFrame->GetProperty(LayerManagerDataProperty()); if (!array) { return nullptr; @@ -5656,7 +5655,7 @@ FrameLayerBuilder::InvalidateAllLayers(LayerManager* aManager) FrameLayerBuilder::InvalidateAllLayersForFrame(nsIFrame *aFrame) { const nsTArray* array = - aFrame->Properties().Get(LayerManagerDataProperty()); + aFrame->GetProperty(LayerManagerDataProperty()); if (array) { for (uint32_t i = 0; i < array->Length(); i++) { AssertDisplayItemData(array->ElementAt(i))->mParent->mInvalidateAllLayers = true; @@ -5673,7 +5672,7 @@ FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, uint32_t aDisplayItemKey) // in the secondary manager const nsTArray* array = - aFrame->Properties().Get(LayerManagerDataProperty()); + aFrame->GetProperty(LayerManagerDataProperty()); if (array) { for (uint32_t i = 0; i < array->Length(); i++) { DisplayItemData *element = AssertDisplayItemData(array->ElementAt(i)); @@ -5729,7 +5728,7 @@ FrameLayerBuilder::GetPaintedLayerScaleForFrame(nsIFrame* aFrame) } const nsTArray* array = - f->Properties().Get(LayerManagerDataProperty()); + f->GetProperty(LayerManagerDataProperty()); if (!array) { continue; } @@ -6165,9 +6164,8 @@ FrameLayerBuilder::GetMostRecentGeometry(nsDisplayItem* aItem) typedef nsTArray DataArray; // Retrieve the array of DisplayItemData associated with our frame. - FrameProperties properties = aItem->Frame()->Properties(); const DataArray* dataArray = - properties.Get(LayerManagerDataProperty()); + aItem->Frame()->GetProperty(LayerManagerDataProperty()); if (!dataArray) { return nullptr; } diff --git a/layout/base/FrameProperties.h b/layout/base/FrameProperties.h new file mode 100644 index 000000000..bba3ee06b --- /dev/null +++ b/layout/base/FrameProperties.h @@ -0,0 +1,440 @@ +/* -*- 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/. */ + +#ifndef FRAMEPROPERTIES_H_ +#define FRAMEPROPERTIES_H_ + +#include "mozilla/DebugOnly.h" +#include "mozilla/MemoryReporting.h" +#include "mozilla/TypeTraits.h" +#include "mozilla/Unused.h" +#include "nsTArray.h" +#include "nsThreadUtils.h" + +class nsIFrame; + +namespace mozilla { + +struct FramePropertyDescriptorUntyped +{ + /** + * mDestructor will be called if it's non-null. + */ + typedef void UntypedDestructor(void* aPropertyValue); + UntypedDestructor* mDestructor; + /** + * mDestructorWithFrame will be called if it's non-null and mDestructor + * is null. WARNING: The frame passed to mDestructorWithFrame may + * be a dangling frame pointer, if this is being called during + * presshell teardown. Do not use it except to compare against + * other frame pointers. No frame will have been allocated with + * the same address yet. + */ + typedef void UntypedDestructorWithFrame(const nsIFrame* aFrame, + void* aPropertyValue); + UntypedDestructorWithFrame* mDestructorWithFrame; + /** + * mDestructor and mDestructorWithFrame may both be null, in which case + * no value destruction is a no-op. + */ + +protected: + /** + * At most one destructor should be passed in. In general, you should + * just use the static function FramePropertyDescriptor::New* below + * instead of using this constructor directly. + */ + constexpr FramePropertyDescriptorUntyped( + UntypedDestructor* aDtor, UntypedDestructorWithFrame* aDtorWithFrame) + : mDestructor(aDtor) + , mDestructorWithFrame(aDtorWithFrame) + {} +}; + +/** + * A pointer to a FramePropertyDescriptor serves as a unique property ID. + * The FramePropertyDescriptor stores metadata about the property. + * Currently the only metadata is a destructor function. The destructor + * function is called on property values when they are overwritten or + * deleted. + * + * To use this class, declare a global (i.e., file, class or function-scope + * static member) FramePropertyDescriptor and pass its address as + * aProperty in the FramePropertyTable methods. + */ +template +struct FramePropertyDescriptor : public FramePropertyDescriptorUntyped +{ + typedef void Destructor(T* aPropertyValue); + typedef void DestructorWithFrame(const nsIFrame* aaFrame, + T* aPropertyValue); + + template + static constexpr const FramePropertyDescriptor NewWithDestructor() + { + return { Destruct, nullptr }; + } + + template + static constexpr + const FramePropertyDescriptor NewWithDestructorWithFrame() + { + return { nullptr, DestructWithFrame }; + } + + static constexpr const FramePropertyDescriptor NewWithoutDestructor() + { + return { nullptr, nullptr }; + } + +private: + constexpr FramePropertyDescriptor( + UntypedDestructor* aDtor, UntypedDestructorWithFrame* aDtorWithFrame) + : FramePropertyDescriptorUntyped(aDtor, aDtorWithFrame) + {} + + template + static void Destruct(void* aPropertyValue) + { + Dtor(static_cast(aPropertyValue)); + } + + template + static void DestructWithFrame(const nsIFrame* aFrame, void* aPropertyValue) + { + Dtor(aFrame, static_cast(aPropertyValue)); + } +}; + +// SmallValueHolder is a placeholder intended to be used as template +// argument of FramePropertyDescriptor for types which can fit into the +// size of a pointer directly. This class should never be defined, so +// that we won't use it for unexpected purpose by mistake. +template +class SmallValueHolder; + +namespace detail { + +template +struct FramePropertyTypeHelper +{ + typedef T* Type; +}; +template +struct FramePropertyTypeHelper> +{ + typedef T Type; +}; + +} + +/** + * The FrameProperties class is optimized for storing 0 or 1 properties on + * a given frame. Storing very large numbers of properties on a single + * frame will not be efficient. + * + * Property values are passed as void* but do not actually have to be + * valid pointers. You can use NS_INT32_TO_PTR/NS_PTR_TO_INT32 to + * store int32_t values. Null/zero values can be stored and retrieved. + * Of course, the destructor function (if any) must handle such values + * correctly. + */ +class FrameProperties +{ +public: + template + using Descriptor = const FramePropertyDescriptor*; + using UntypedDescriptor = const FramePropertyDescriptorUntyped*; + + template + using PropertyType = typename detail::FramePropertyTypeHelper::Type; + + explicit FrameProperties() + { + } + + ~FrameProperties() + { + MOZ_ASSERT(mProperties.Length() == 0, "forgot to delete properties"); + } + + /** + * Set a property value. This requires a linear search through + * the properties of the frame. Any existing value for the property + * is destroyed. + */ + template + void Set(Descriptor aProperty, PropertyType aValue, + const nsIFrame* aFrame) + { + void* ptr = ReinterpretHelper::ToPointer(aValue); + SetInternal(aProperty, ptr, aFrame); + } + + /** + * @return true if @aProperty is set. This requires a linear search through the + * properties of the frame. + * + * In most cases, this shouldn't be used outside of assertions, because if + * you're doing a lookup anyway it would be far more efficient to call Get() + * or Remove() and check the aFoundResult outparam to find out whether the + * property is set. Legitimate non-assertion uses include: + * + * - Checking if a frame property is set in cases where that's all we want + * to know (i.e., we don't intend to read the actual value or remove the + * property). + * + * - Calling Has() before Set() in cases where we don't want to overwrite + * an existing value for the frame property. + */ + template + bool Has(Descriptor aProperty) const + { + return mProperties.IndexOf(aProperty, 0, PropertyComparator()) != nsTArray::NoIndex; + } + + /** + * Get a property value. This requires a linear search through + * lookup (using the frame as the key) and a linear search through + * the properties of the frame. If the frame has no such property, + * returns zero-filled result, which means null for pointers and + * zero for integers and floating point types. + * @param aFoundResult if non-null, receives a value 'true' iff + * the frame has a value for the property. This lets callers + * disambiguate a null result, which can mean 'no such property' or + * 'property value is null'. + */ + template + PropertyType Get(Descriptor aProperty, + bool* aFoundResult = nullptr) const + { + void* ptr = GetInternal(aProperty, aFoundResult); + return ReinterpretHelper::FromPointer(ptr); + } + /** + * Remove a property value. This requires a linear search through + * the properties of the frame. The old property value is returned + * (and not destroyed). If the frame has no such property, + * returns zero-filled result, which means null for pointers and + * zero for integers and floating point types. + * @param aFoundResult if non-null, receives a value 'true' iff + * the frame had a value for the property. This lets callers + * disambiguate a null result, which can mean 'no such property' or + * 'property value is null'. + */ + template + PropertyType Remove(Descriptor aProperty, + bool* aFoundResult = nullptr) + { + void* ptr = RemoveInternal(aProperty, aFoundResult); + return ReinterpretHelper::FromPointer(ptr); + } + /** + * Remove and destroy a property value. This requires a linear search + * through the properties of the frame. If the frame has no such + * property, nothing happens. + */ + template + void Delete(Descriptor aProperty, const nsIFrame* aFrame) + { + DeleteInternal(aProperty, aFrame); + } + /** + * Remove and destroy all property values for the frame. + */ + void DeleteAll(const nsIFrame* aFrame) { + mozilla::DebugOnly len = mProperties.Length(); + for (auto& prop : mProperties) { + prop.DestroyValueFor(aFrame); + MOZ_ASSERT(mProperties.Length() == len); + } + mProperties.Clear(); + } + + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { + // We currently report only the shallow size of the mProperties array. + // As for the PropertyValue entries: we don't need to measure the mProperty + // field of because it always points to static memory, and we can't measure + // mValue because the type is opaque. + // XXX Can we do better, e.g. with a method on the descriptor? + return mProperties.ShallowSizeOfExcludingThis(aMallocSizeOf); + } + +private: + friend class ::nsIFrame; + + // Prevent copying of FrameProperties; we should always return/pass around + // references to it, not copies! + FrameProperties(const FrameProperties&) = delete; + FrameProperties& operator=(const FrameProperties&) = delete; + + inline void + SetInternal(UntypedDescriptor aProperty, void* aValue, + const nsIFrame* aFrame); + + inline void* + GetInternal(UntypedDescriptor aProperty, bool* aFoundResult) const; + + inline void* + RemoveInternal(UntypedDescriptor aProperty, bool* aFoundResult); + + inline void + DeleteInternal(UntypedDescriptor aProperty, const nsIFrame* aFrame); + + template + struct ReinterpretHelper + { + static_assert(sizeof(PropertyType) <= sizeof(void*), + "size of the value must never be larger than a pointer"); + + static void* ToPointer(PropertyType aValue) + { + void* ptr = nullptr; + memcpy(&ptr, &aValue, sizeof(aValue)); + return ptr; + } + + static PropertyType FromPointer(void* aPtr) + { + PropertyType value; + memcpy(&value, &aPtr, sizeof(value)); + return value; + } + }; + + template + struct ReinterpretHelper + { + static void* ToPointer(T* aValue) + { + return static_cast(aValue); + } + + static T* FromPointer(void* aPtr) + { + return static_cast(aPtr); + } + }; + + /** + * Stores a property descriptor/value pair. + */ + struct PropertyValue { + PropertyValue() : mProperty(nullptr), mValue(nullptr) {} + PropertyValue(UntypedDescriptor aProperty, void* aValue) + : mProperty(aProperty), mValue(aValue) {} + + void DestroyValueFor(const nsIFrame* aFrame) { + if (mProperty->mDestructor) { + mProperty->mDestructor(mValue); + } else if (mProperty->mDestructorWithFrame) { + mProperty->mDestructorWithFrame(aFrame, mValue); + } + } + + UntypedDescriptor mProperty; + void* mValue; + }; + + /** + * Used with an array of PropertyValues to allow lookups that compare + * only on the FramePropertyDescriptor. + */ + class PropertyComparator { + public: + bool Equals(const PropertyValue& a, const PropertyValue& b) const { + return a.mProperty == b.mProperty; + } + bool Equals(UntypedDescriptor a, const PropertyValue& b) const { + return a == b.mProperty; + } + bool Equals(const PropertyValue& a, UntypedDescriptor b) const { + return a.mProperty == b; + } + }; + + nsTArray mProperties; +}; + +/** + * This class encapsulates the properties of a frame. + */ +inline void* +FrameProperties::GetInternal(UntypedDescriptor aProperty, + bool* aFoundResult) const +{ + MOZ_ASSERT(aProperty, "Null property?"); + + auto index = mProperties.IndexOf(aProperty, 0, PropertyComparator()); + if (index == nsTArray::NoIndex) { + if (aFoundResult) { + *aFoundResult = false; + } + return nullptr; + } + + if (aFoundResult) { + *aFoundResult = true; + } + +return mProperties.ElementAt(index).mValue; +} + +inline void +FrameProperties::SetInternal(UntypedDescriptor aProperty, void* aValue, + const nsIFrame* aFrame) +{ + MOZ_ASSERT(aProperty, "Null property?"); + + auto index = mProperties.IndexOf(aProperty, 0, PropertyComparator()); + if (index != nsTArray::NoIndex) { + PropertyValue* pv = &mProperties.ElementAt(index); + pv->DestroyValueFor(aFrame); + pv->mValue = aValue; + return; + } + + mProperties.AppendElement(PropertyValue(aProperty, aValue)); +} + +inline void* +FrameProperties::RemoveInternal(UntypedDescriptor aProperty, bool* aFoundResult) +{ + MOZ_ASSERT(aProperty, "Null property?"); + + auto index = mProperties.IndexOf(aProperty, 0, PropertyComparator()); + if (index == nsTArray::NoIndex) { + if (aFoundResult) { + *aFoundResult = false; + } + return nullptr; + } + +if (aFoundResult) { + *aFoundResult = true; +} + +void* result = mProperties.ElementAt(index).mValue; +mProperties.RemoveElementAt(index); + +return result; +} + +inline void +FrameProperties::DeleteInternal(UntypedDescriptor aProperty, + const nsIFrame* aFrame) +{ + MOZ_ASSERT(aProperty, "Null property?"); + + auto index = mProperties.IndexOf(aProperty, 0, PropertyComparator()); + if (index != nsTArray::NoIndex) { + mProperties.ElementAt(index).DestroyValueFor(aFrame); + mProperties.RemoveElementAt(index); + } +} + +} // namespace mozilla + +#endif /* FRAMEPROPERTIES_H_ */ diff --git a/layout/base/FramePropertyTable.cpp b/layout/base/FramePropertyTable.cpp deleted file mode 100644 index 0fd9b1c37..000000000 --- a/layout/base/FramePropertyTable.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/* -*- 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) <= sizeof(void *), - "Property array must fit entirely within entry->mProp.mValue"); - new (&entry->mProp.mValue) nsTArray(4); - entry->mProp.ToArray()->AppendElement(current); - } - - nsTArray* array = entry->mProp.ToArray(); - nsTArray::index_type index = - array->IndexOf(aProperty, 0, PropertyComparator()); - if (index != nsTArray::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* array = entry->mProp.ToArray(); - nsTArray::index_type index = - array->IndexOf(aProperty, 0, PropertyComparator()); - if (index == nsTArray::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* array = entry->mProp.ToArray(); - nsTArray::index_type index = - array->IndexOf(aProperty, 0, PropertyComparator()); - if (index == nsTArray::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(); - 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* array = aEntry->mProp.ToArray(); - for (uint32_t i = 0; i < array->Length(); ++i) { - array->ElementAt(i).DestroyValueFor(aEntry->GetKey()); - } - array->~nsTArray(); -} - -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 diff --git a/layout/base/FramePropertyTable.h b/layout/base/FramePropertyTable.h deleted file mode 100644 index e9847efbf..000000000 --- a/layout/base/FramePropertyTable.h +++ /dev/null @@ -1,442 +0,0 @@ -/* -*- 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/. */ - -#ifndef FRAMEPROPERTYTABLE_H_ -#define FRAMEPROPERTYTABLE_H_ - -#include "mozilla/MemoryReporting.h" -#include "mozilla/TypeTraits.h" -#include "mozilla/Unused.h" -#include "nsTArray.h" -#include "nsTHashtable.h" -#include "nsHashKeys.h" - -class nsIFrame; - -namespace mozilla { - -struct FramePropertyDescriptorUntyped -{ - /** - * mDestructor will be called if it's non-null. - */ - typedef void UntypedDestructor(void* aPropertyValue); - UntypedDestructor* mDestructor; - /** - * mDestructorWithFrame will be called if it's non-null and mDestructor - * is null. WARNING: The frame passed to mDestructorWithFrame may - * be a dangling frame pointer, if this is being called during - * presshell teardown. Do not use it except to compare against - * other frame pointers. No frame will have been allocated with - * the same address yet. - */ - typedef void UntypedDestructorWithFrame(const nsIFrame* aFrame, - void* aPropertyValue); - UntypedDestructorWithFrame* mDestructorWithFrame; - /** - * mDestructor and mDestructorWithFrame may both be null, in which case - * no value destruction is a no-op. - */ - -protected: - /** - * At most one destructor should be passed in. In general, you should - * just use the static function FramePropertyDescriptor::New* below - * instead of using this constructor directly. - */ - constexpr FramePropertyDescriptorUntyped( - UntypedDestructor* aDtor, UntypedDestructorWithFrame* aDtorWithFrame) - : mDestructor(aDtor) - , mDestructorWithFrame(aDtorWithFrame) - {} -}; - -/** - * A pointer to a FramePropertyDescriptor serves as a unique property ID. - * The FramePropertyDescriptor stores metadata about the property. - * Currently the only metadata is a destructor function. The destructor - * function is called on property values when they are overwritten or - * deleted. - * - * To use this class, declare a global (i.e., file, class or function-scope - * static member) FramePropertyDescriptor and pass its address as - * aProperty in the FramePropertyTable methods. - */ -template -struct FramePropertyDescriptor : public FramePropertyDescriptorUntyped -{ - typedef void Destructor(T* aPropertyValue); - typedef void DestructorWithFrame(const nsIFrame* aaFrame, - T* aPropertyValue); - - template - static constexpr const FramePropertyDescriptor NewWithDestructor() - { - return { Destruct, nullptr }; - } - - template - static constexpr - const FramePropertyDescriptor NewWithDestructorWithFrame() - { - return { nullptr, DestructWithFrame }; - } - - static constexpr const FramePropertyDescriptor NewWithoutDestructor() - { - return { nullptr, nullptr }; - } - -private: - constexpr FramePropertyDescriptor( - UntypedDestructor* aDtor, UntypedDestructorWithFrame* aDtorWithFrame) - : FramePropertyDescriptorUntyped(aDtor, aDtorWithFrame) - {} - - template - static void Destruct(void* aPropertyValue) - { - Dtor(static_cast(aPropertyValue)); - } - - template - static void DestructWithFrame(const nsIFrame* aFrame, void* aPropertyValue) - { - Dtor(aFrame, static_cast(aPropertyValue)); - } -}; - -// SmallValueHolder is a placeholder intended to be used as template -// argument of FramePropertyDescriptor for types which can fit into the -// size of a pointer directly. This class should never be defined, so -// that we won't use it for unexpected purpose by mistake. -template -class SmallValueHolder; - -namespace detail { - -template -struct FramePropertyTypeHelper -{ - typedef T* Type; -}; -template -struct FramePropertyTypeHelper> -{ - typedef T Type; -}; - -} - -/** - * The FramePropertyTable is optimized for storing 0 or 1 properties on - * a given frame. Storing very large numbers of properties on a single - * frame will not be efficient. - * - * Property values are passed as void* but do not actually have to be - * valid pointers. You can use NS_INT32_TO_PTR/NS_PTR_TO_INT32 to - * store int32_t values. Null/zero values can be stored and retrieved. - * Of course, the destructor function (if any) must handle such values - * correctly. - */ -class FramePropertyTable { -public: - template - using Descriptor = const FramePropertyDescriptor*; - using UntypedDescriptor = const FramePropertyDescriptorUntyped*; - - template - using PropertyType = typename detail::FramePropertyTypeHelper::Type; - - FramePropertyTable() : mLastFrame(nullptr), mLastEntry(nullptr) - { - } - ~FramePropertyTable() - { - DeleteAll(); - } - - /** - * Set a property value on a frame. This requires one hashtable - * lookup (using the frame as the key) and a linear search through - * the properties of that frame. Any existing value for the property - * is destroyed. - */ - template - void Set(const nsIFrame* aFrame, Descriptor aProperty, - PropertyType aValue) - { - void* ptr = ReinterpretHelper::ToPointer(aValue); - SetInternal(aFrame, aProperty, ptr); - } - - /** - * @return true if @aProperty is set for @aFrame. This requires one hashtable - * lookup (using the frame as the key) and a linear search through the - * properties of that frame. - * - * In most cases, this shouldn't be used outside of assertions, because if - * you're doing a lookup anyway it would be far more efficient to call Get() - * or Remove() and check the aFoundResult outparam to find out whether the - * property is set. Legitimate non-assertion uses include: - * - * - Checking if a frame property is set in cases where that's all we want - * to know (i.e., we don't intend to read the actual value or remove the - * property). - * - * - Calling Has() before Set() in cases where we don't want to overwrite - * an existing value for the frame property. - */ - template - bool Has(const nsIFrame* aFrame, Descriptor aProperty) - { - bool foundResult = false; - mozilla::Unused << GetInternal(aFrame, aProperty, &foundResult); - return foundResult; - } - - /** - * Get a property value for a frame. This requires one hashtable - * lookup (using the frame as the key) and a linear search through - * the properties of that frame. If the frame has no such property, - * returns zero-filled result, which means null for pointers and - * zero for integers and floating point types. - * @param aFoundResult if non-null, receives a value 'true' iff - * the frame has a value for the property. This lets callers - * disambiguate a null result, which can mean 'no such property' or - * 'property value is null'. - */ - template - PropertyType Get(const nsIFrame* aFrame, Descriptor aProperty, - bool* aFoundResult = nullptr) - { - void* ptr = GetInternal(aFrame, aProperty, aFoundResult); - return ReinterpretHelper::FromPointer(ptr); - } - /** - * Remove a property value for a frame. This requires one hashtable - * lookup (using the frame as the key) and a linear search through - * the properties of that frame. The old property value is returned - * (and not destroyed). If the frame has no such property, - * returns zero-filled result, which means null for pointers and - * zero for integers and floating point types. - * @param aFoundResult if non-null, receives a value 'true' iff - * the frame had a value for the property. This lets callers - * disambiguate a null result, which can mean 'no such property' or - * 'property value is null'. - */ - template - PropertyType Remove(const nsIFrame* aFrame, Descriptor aProperty, - bool* aFoundResult = nullptr) - { - void* ptr = RemoveInternal(aFrame, aProperty, aFoundResult); - return ReinterpretHelper::FromPointer(ptr); - } - /** - * Remove and destroy a property value for a frame. This requires one - * hashtable lookup (using the frame as the key) and a linear search - * through the properties of that frame. If the frame has no such - * property, nothing happens. - */ - template - void Delete(const nsIFrame* aFrame, Descriptor aProperty) - { - DeleteInternal(aFrame, aProperty); - } - /** - * Remove and destroy all property values for a frame. This requires one - * hashtable lookup (using the frame as the key). - */ - void DeleteAllFor(const nsIFrame* aFrame); - /** - * Remove and destroy all property values for all frames. - */ - void DeleteAll(); - - size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; - -protected: - void SetInternal(const nsIFrame* aFrame, UntypedDescriptor aProperty, - void* aValue); - - void* GetInternal(const nsIFrame* aFrame, UntypedDescriptor aProperty, - bool* aFoundResult); - - void* RemoveInternal(const nsIFrame* aFrame, UntypedDescriptor aProperty, - bool* aFoundResult); - - void DeleteInternal(const nsIFrame* aFrame, UntypedDescriptor aProperty); - - template - struct ReinterpretHelper - { - static_assert(sizeof(PropertyType) <= sizeof(void*), - "size of the value must never be larger than a pointer"); - - static void* ToPointer(PropertyType aValue) - { - void* ptr = nullptr; - memcpy(&ptr, &aValue, sizeof(aValue)); - return ptr; - } - - static PropertyType FromPointer(void* aPtr) - { - PropertyType value; - memcpy(&value, &aPtr, sizeof(value)); - return value; - } - }; - - template - struct ReinterpretHelper - { - static void* ToPointer(T* aValue) - { - return static_cast(aValue); - } - - static T* FromPointer(void* aPtr) - { - return static_cast(aPtr); - } - }; - - /** - * Stores a property descriptor/value pair. It can also be used to - * store an nsTArray of PropertyValues. - */ - struct PropertyValue { - PropertyValue() : mProperty(nullptr), mValue(nullptr) {} - PropertyValue(UntypedDescriptor aProperty, void* aValue) - : mProperty(aProperty), mValue(aValue) {} - - bool IsArray() { return !mProperty && mValue; } - nsTArray* ToArray() - { - NS_ASSERTION(IsArray(), "Must be array"); - return reinterpret_cast*>(&mValue); - } - - void DestroyValueFor(const nsIFrame* aFrame) { - if (mProperty->mDestructor) { - mProperty->mDestructor(mValue); - } else if (mProperty->mDestructorWithFrame) { - mProperty->mDestructorWithFrame(aFrame, mValue); - } - } - - size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) { - size_t n = 0; - // We don't need to measure mProperty because it always points to static - // memory. As for mValue: if it's a single value we can't measure it, - // because the type is opaque; if it's an array, we measure the array - // storage, but we can't measure the individual values, again because - // their types are opaque. - if (IsArray()) { - nsTArray* array = ToArray(); - n += array->ShallowSizeOfExcludingThis(aMallocSizeOf); - } - return n; - } - - UntypedDescriptor mProperty; - void* mValue; - }; - - /** - * Used with an array of PropertyValues to allow lookups that compare - * only on the FramePropertyDescriptor. - */ - class PropertyComparator { - public: - bool Equals(const PropertyValue& a, const PropertyValue& b) const { - return a.mProperty == b.mProperty; - } - bool Equals(UntypedDescriptor a, const PropertyValue& b) const { - return a == b.mProperty; - } - bool Equals(const PropertyValue& a, UntypedDescriptor b) const { - return a.mProperty == b; - } - }; - - /** - * Our hashtable entry. The key is an nsIFrame*, the value is a - * PropertyValue representing one or more property/value pairs. - */ - class Entry : public nsPtrHashKey - { - public: - explicit Entry(KeyTypePointer aKey) : nsPtrHashKey(aKey) {} - Entry(const Entry &toCopy) : - nsPtrHashKey(toCopy), mProp(toCopy.mProp) {} - - size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) { - return mProp.SizeOfExcludingThis(aMallocSizeOf); - } - - PropertyValue mProp; - }; - - static void DeleteAllForEntry(Entry* aEntry); - - // Note that mLastEntry points into mEntries, so we need to be careful about - // not triggering a resize of mEntries, e.g. use RawRemoveEntry() instead of - // RemoveEntry() in some places. - nsTHashtable mEntries; - const nsIFrame* mLastFrame; - Entry* mLastEntry; -}; - -/** - * This class encapsulates the properties of a frame. - */ -class FrameProperties { -public: - template using Descriptor = FramePropertyTable::Descriptor; - template using PropertyType = FramePropertyTable::PropertyType; - - FrameProperties(FramePropertyTable* aTable, const nsIFrame* aFrame) - : mTable(aTable), mFrame(aFrame) {} - - template - void Set(Descriptor aProperty, PropertyType aValue) const - { - mTable->Set(mFrame, aProperty, aValue); - } - - template - bool Has(Descriptor aProperty) const - { - return mTable->Has(mFrame, aProperty); - } - - template - PropertyType Get(Descriptor aProperty, - bool* aFoundResult = nullptr) const - { - return mTable->Get(mFrame, aProperty, aFoundResult); - } - template - PropertyType Remove(Descriptor aProperty, - bool* aFoundResult = nullptr) const - { - return mTable->Remove(mFrame, aProperty, aFoundResult); - } - template - void Delete(Descriptor aProperty) - { - mTable->Delete(mFrame, aProperty); - } - -private: - FramePropertyTable* mTable; - const nsIFrame* mFrame; -}; - -} // namespace mozilla - -#endif /* FRAMEPROPERTYTABLE_H_ */ diff --git a/layout/base/OverflowChangedTracker.h b/layout/base/OverflowChangedTracker.h index a18d64b46..40145c65c 100644 --- a/layout/base/OverflowChangedTracker.h +++ b/layout/base/OverflowChangedTracker.h @@ -112,12 +112,12 @@ public: // Take a faster path that doesn't require unioning the overflow areas // of our children. - NS_ASSERTION(frame->Properties().Get( + NS_ASSERTION(frame->GetProperty( nsIFrame::DebugInitialOverflowPropertyApplied()), "InitialOverflowProperty must be set first."); nsOverflowAreas* overflow = - frame->Properties().Get(nsIFrame::InitialOverflowProperty()); + frame->GetProperty(nsIFrame::InitialOverflowProperty()); if (overflow) { // FinishAndStoreOverflow will change the overflow areas passed in, // so make a copy. diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index de8f10224..124b5535e 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -1122,10 +1122,10 @@ GetPrevContinuationWithPossiblySameStyle(nsIFrame* aFrame) // We're the first continuation, so we can just get the frame // property directly prevContinuation = - aFrame->Properties().Get(nsIFrame::IBSplitPrevSibling()); + aFrame->GetProperty(nsIFrame::IBSplitPrevSibling()); if (prevContinuation) { prevContinuation = - prevContinuation->Properties().Get(nsIFrame::IBSplitPrevSibling()); + prevContinuation->GetProperty(nsIFrame::IBSplitPrevSibling()); } } @@ -1313,8 +1313,7 @@ RestyleManager::ReparentStyleContext(nsIFrame* aFrame) // oldContext)" check will prevent us from redoing work. if ((aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) && !aFrame->GetPrevContinuation()) { - nsIFrame* sib = - aFrame->Properties().Get(nsIFrame::IBSplitSibling()); + nsIFrame* sib = aFrame->GetProperty(nsIFrame::IBSplitSibling()); if (sib) { ReparentStyleContext(sib); } @@ -3349,7 +3348,6 @@ ElementRestyler::ComputeStyleChangeFor(nsIFrame* aFrame, // line), we might restyle more than that. nsPresContext* presContext = aFrame->PresContext(); - FramePropertyTable* propTable = presContext->PropertyTable(); TreeMatchContext treeMatchContext(true, nsRuleWalker::eRelevantLinkUnvisited, @@ -3363,7 +3361,7 @@ ElementRestyler::ComputeStyleChangeFor(nsIFrame* aFrame, nsTArray visibleKidsOfHiddenElement; nsIFrame* nextIBSibling; for (nsIFrame* ibSibling = aFrame; ibSibling; ibSibling = nextIBSibling) { - nextIBSibling = RestyleManager::GetNextBlockInInlineSibling(propTable, ibSibling); + nextIBSibling = RestyleManager::GetNextBlockInInlineSibling(ibSibling); if (nextIBSibling) { // Don't allow some ib-split siblings to be processed with diff --git a/layout/base/RestyleManagerBase.cpp b/layout/base/RestyleManagerBase.cpp index d96d9dbbb..6770f9464 100644 --- a/layout/base/RestyleManagerBase.cpp +++ b/layout/base/RestyleManagerBase.cpp @@ -385,8 +385,6 @@ RestyleManagerBase::DebugVerifyStyleTree(nsIFrame* aFrame) #endif // DEBUG -NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(ChangeListProperty, bool) - /** * Sync views on aFrame and all of aFrame's descendants (following placeholders), * if aChange has nsChangeHint_SyncFrameView. @@ -521,10 +519,9 @@ RecomputePosition(nsIFrame* aFrame) // normal position, go ahead and add the offsets directly. // First, we need to ensure that the normal position is stored though. nsPoint normalPosition = cont->GetNormalPosition(); - auto props = cont->Properties(); - const auto& prop = nsIFrame::NormalPositionProperty(); - if (!props.Get(prop)) { - props.Set(prop, new nsPoint(normalPosition)); + if (!cont->GetProperty(nsIFrame::NormalPositionProperty())) { + cont->SetProperty(nsIFrame::NormalPositionProperty(), + new nsPoint(normalPosition)); } cont->SetPosition(normalPosition + nsPoint(newOffsets.left, newOffsets.top)); @@ -739,8 +736,7 @@ RestyleManagerBase::GetNearestAncestorFrame(nsIContent* aContent) } /* static */ nsIFrame* -RestyleManagerBase::GetNextBlockInInlineSibling(FramePropertyTable* aPropTable, - nsIFrame* aFrame) +RestyleManagerBase::GetNextBlockInInlineSibling(nsIFrame* aFrame) { NS_ASSERTION(!aFrame->GetPrevContinuation(), "must start with the first continuation"); @@ -750,8 +746,7 @@ RestyleManagerBase::GetNextBlockInInlineSibling(FramePropertyTable* aPropTable, return nullptr; } - return static_cast - (aPropTable->Get(aFrame, nsIFrame::IBSplitSibling())); + return aFrame->GetProperty(nsIFrame::IBSplitSibling()); } static void @@ -1028,10 +1023,10 @@ RestyleManagerBase::GetNextContinuationWithSameStyle( // We're the last continuation, so we have to hop back to the first // before getting the frame property nextContinuation = - aFrame->FirstContinuation()->Properties().Get(nsIFrame::IBSplitSibling()); + aFrame->FirstContinuation()->GetProperty(nsIFrame::IBSplitSibling()); if (nextContinuation) { nextContinuation = - nextContinuation->Properties().Get(nsIFrame::IBSplitSibling()); + nextContinuation->GetProperty(nsIFrame::IBSplitSibling()); } } @@ -1060,14 +1055,52 @@ RestyleManagerBase::ProcessRestyledFrames(nsStyleChangeList& aChangeList) { NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), "Someone forgot a script blocker"); - if (aChangeList.IsEmpty()) - return NS_OK; + +// See bug 1378219 comment 9: +// Recursive calls here are a bit worrying, but apparently do happen in the +// wild (although not currently in any of our automated tests). Try to get a +// stack from Nightly/Dev channel to figure out what's going on and whether +// it's OK. +MOZ_DIAGNOSTIC_ASSERT(!mDestroyedFrames, "ProcessRestyledFrames recursion"); + +if (aChangeList.IsEmpty()) + return NS_OK; + +// If mDestroyedFrames is null, we want to create a new hashtable here +// and destroy it on exit; but if it is already non-null (because we're in +// a recursive call), we will continue to use the existing table to +// accumulate destroyed frames, and NOT clear mDestroyedFrames on exit. +// We use a MaybeClearDestroyedFrames helper to conditionally reset the +// mDestroyedFrames pointer when this method returns. +typedef decltype(mDestroyedFrames) DestroyedFramesT; +class MOZ_RAII MaybeClearDestroyedFrames +{ +private: + DestroyedFramesT& mDestroyedFramesRef; // ref to caller's mDestroyedFrames + const bool mResetOnDestruction; +public: + explicit MaybeClearDestroyedFrames(DestroyedFramesT& aTarget) + : mDestroyedFramesRef(aTarget) + , mResetOnDestruction(!aTarget) // reset only if target starts out null + { + } + ~MaybeClearDestroyedFrames() + { + if (mResetOnDestruction) { + mDestroyedFramesRef.reset(nullptr); + } + } +}; + +MaybeClearDestroyedFrames maybeClear(mDestroyedFrames); +if (!mDestroyedFrames) { + mDestroyedFrames = MakeUnique>>(); +} PROFILER_LABEL("RestyleManager", "ProcessRestyledFrames", js::ProfileEntry::Category::CSS); nsPresContext* presContext = PresContext(); - FramePropertyTable* propTable = presContext->PropertyTable(); nsCSSFrameConstructor* frameConstructor = presContext->FrameConstructor(); // Handle nsChangeHint_CSSOverflowChange, by either updating the @@ -1135,15 +1168,6 @@ RestyleManagerBase::ProcessRestyledFrames(nsStyleChangeList& aChangeList) // processing restyles frameConstructor->BeginUpdate(); - // Mark frames so that we skip frames that die along the way, bug 123049. - // A frame can be in the list multiple times with different hints. Further - // optmization is possible if nsStyleChangeList::AppendChange could coalesce - for (const nsStyleChangeData& data : aChangeList) { - if (data.mFrame) { - propTable->Set(data.mFrame, ChangeListProperty(), true); - } - } - bool didUpdateCursor = false; for (const nsStyleChangeData& data : aChangeList) { @@ -1157,7 +1181,7 @@ RestyleManagerBase::ProcessRestyledFrames(nsStyleChangeList& aChangeList) "Reflow hint bits set without actually asking for a reflow"); // skip any frame that has been destroyed due to a ripple effect - if (frame && !propTable->Get(frame, ChangeListProperty())) { + if (frame && mDestroyedFrames->Contains(frame)) { continue; } @@ -1409,15 +1433,11 @@ RestyleManagerBase::ProcessRestyledFrames(nsStyleChangeList& aChangeList) frameConstructor->EndUpdate(); - // cleanup references and verify the style tree. Note that the latter needs - // to happen once we've processed the whole list, since until then the tree - // is not in fact in a consistent state. - for (const nsStyleChangeData& data : aChangeList) { - if (data.mFrame) { - propTable->Delete(data.mFrame, ChangeListProperty()); - } - #ifdef DEBUG + // Verify the style tree. Note that this needs to happen once we've + // processed the whole list, since until then the tree is not in fact in a + // consistent state. + for (const nsStyleChangeData& data : aChangeList) { // reget frame from content since it may have been regenerated... if (data.mContent) { nsIFrame* frame = data.mContent->GetPrimaryFrame(); @@ -1429,8 +1449,8 @@ RestyleManagerBase::ProcessRestyledFrames(nsStyleChangeList& aChangeList) NS_WARNING("Unable to test style tree integrity -- no content node " "(and not a viewport frame)"); } -#endif } +#endif aChangeList.Clear(); return NS_OK; diff --git a/layout/base/RestyleManagerBase.h b/layout/base/RestyleManagerBase.h index f81f5e73f..d92c3d1f7 100644 --- a/layout/base/RestyleManagerBase.h +++ b/layout/base/RestyleManagerBase.h @@ -72,6 +72,11 @@ public: // WillDestroyFrameTree hasn't been called yet. void NotifyDestroyingFrame(nsIFrame* aFrame) { mOverflowChangedTracker.RemoveFrame(aFrame); + // If ProcessRestyledFrames is tracking frames which have been + // destroyed (to avoid re-visiting them), add this one to its set. + if (mDestroyedFrames) { + mDestroyedFrames->PutEntry(aFrame); + } } // Note: It's the caller's responsibility to make sure to wrap a @@ -127,6 +132,12 @@ private: nsPresContext* mPresContext; // weak, can be null after Disconnect(). uint32_t mRestyleGeneration; uint32_t mHoverGeneration; + + // Used to keep track of frames that have been destroyed during + // ProcessRestyledFrames, so we don't try to touch them again even if + // they're referenced again later in the changelist. + mozilla::UniquePtr>> mDestroyedFrames; + // True if we're already waiting for a refresh notification. bool mObservingRefreshDriver; @@ -146,7 +157,7 @@ protected: GetNearestAncestorFrame(nsIContent* aContent); static nsIFrame* - GetNextBlockInInlineSibling(FramePropertyTable* aPropTable, nsIFrame* aFrame); + GetNextBlockInInlineSibling(nsIFrame* aFrame); /** * Get the next continuation or similar ib-split sibling (assuming diff --git a/layout/base/moz.build b/layout/base/moz.build index d3e417f16..4308a6e4d 100644 --- a/layout/base/moz.build +++ b/layout/base/moz.build @@ -61,7 +61,7 @@ EXPORTS += [ 'DisplayItemScrollClip.h', 'DisplayListClipState.h', 'FrameLayerBuilder.h', - 'FramePropertyTable.h', + 'FrameProperties.h', 'LayerState.h', 'LayoutLogging.h', 'nsArenaMemoryStats.h', @@ -126,7 +126,6 @@ UNIFIED_SOURCES += [ 'DisplayListClipState.cpp', 'DottedCornerFinder.cpp', 'FrameLayerBuilder.cpp', - 'FramePropertyTable.cpp', 'GeometryUtils.cpp', 'LayoutLogging.cpp', 'MaskLayerImageCache.cpp', diff --git a/layout/base/nsBidiPresUtils.cpp b/layout/base/nsBidiPresUtils.cpp index b3c20aabb..887563504 100644 --- a/layout/base/nsBidiPresUtils.cpp +++ b/layout/base/nsBidiPresUtils.cpp @@ -753,7 +753,6 @@ nsBidiPresUtils::ResolveParagraph(BidiParagraphData* aBpd) nsIContent* content = nullptr; int32_t contentTextLength = 0; - FramePropertyTable* propTable = aBpd->mPresContext->PropertyTable(); nsLineBox* currentLine = nullptr; #ifdef DEBUG @@ -809,7 +808,7 @@ nsBidiPresUtils::ResolveParagraph(BidiParagraphData* aBpd) } precedingControl = kBidiLevelNone; lastEmbedingLevel = embeddingLevel; - propTable->Set(frame, nsIFrame::BidiDataProperty(), bidiData); + frame->SetProperty(nsIFrame::BidiDataProperty(), bidiData); }; for (; ;) { @@ -1787,7 +1786,7 @@ nsBidiPresUtils::RemoveBidiContinuation(BidiParagraphData *aBpd, if (frame != NS_BIDI_CONTROL_FRAME) { // Make the frame and its continuation ancestors fluid, // so they can be reused or deleted by normal reflow code - frame->Properties().Set(nsIFrame::BidiDataProperty(), bidiData); + frame->SetProperty(nsIFrame::BidiDataProperty(), bidiData); frame->AddStateBits(NS_FRAME_IS_BIDI); while (frame) { nsIFrame* prev = frame->GetPrevContinuation(); diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 07a5b80e7..ec676ca92 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -492,9 +492,8 @@ static nsContainerFrame* GetIBSplitSibling(nsIFrame* aFrame) // We only store the "ib-split sibling" annotation with the first // frame in the continuation chain. Walk back to find that frame now. - return static_cast - (aFrame->FirstContinuation()-> - Properties().Get(nsIFrame::IBSplitSibling())); + return aFrame->FirstContinuation()-> + GetProperty(nsIFrame::IBSplitSibling()); } static nsContainerFrame* GetIBSplitPrevSibling(nsIFrame* aFrame) @@ -503,9 +502,8 @@ static nsContainerFrame* GetIBSplitPrevSibling(nsIFrame* aFrame) // We only store the ib-split sibling annotation with the first // frame in the continuation chain. Walk back to find that frame now. - return static_cast - (aFrame->FirstContinuation()-> - Properties().Get(nsIFrame::IBSplitPrevSibling())); + return aFrame->FirstContinuation()-> + GetProperty(nsIFrame::IBSplitPrevSibling()); } static nsContainerFrame* @@ -526,7 +524,7 @@ GetLastIBSplitSibling(nsIFrame* aFrame, bool aReturnEmptyTrailingInline) } static void -SetFrameIsIBSplit(nsContainerFrame* aFrame, nsIFrame* aIBSplitSibling) +SetFrameIsIBSplit(nsContainerFrame* aFrame, nsContainerFrame* aIBSplitSibling) { NS_PRECONDITION(aFrame, "bad args!"); @@ -547,9 +545,8 @@ SetFrameIsIBSplit(nsContainerFrame* aFrame, nsIFrame* aIBSplitSibling) // Store the ib-split sibling (if we were given one) with the // first frame in the flow. - FramePropertyTable* props = aFrame->PresContext()->PropertyTable(); - props->Set(aFrame, nsIFrame::IBSplitSibling(), aIBSplitSibling); - props->Set(aIBSplitSibling, nsIFrame::IBSplitPrevSibling(), aFrame); + aFrame->SetProperty(nsIFrame::IBSplitSibling(), aIBSplitSibling); + aIBSplitSibling->SetProperty(nsIFrame::IBSplitPrevSibling(), aFrame); } } @@ -6075,11 +6072,11 @@ AddGenConPseudoToFrame(nsIFrame* aOwnerFrame, nsIContent* aContent) NS_ASSERTION(nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(aOwnerFrame), "property should only be set on first continuation/ib-sibling"); - FrameProperties props = aOwnerFrame->Properties(); - nsIFrame::ContentArray* value = props.Get(nsIFrame::GenConProperty()); + nsIFrame::ContentArray* value = + aOwnerFrame->GetProperty(nsIFrame::GenConProperty()); if (!value) { value = new nsIFrame::ContentArray; - props.Set(nsIFrame::GenConProperty(), value); + aOwnerFrame->SetProperty(nsIFrame::GenConProperty(), value); } value->AppendElement(aContent); } diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index ff9edf742..119c6c8a2 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -293,13 +293,13 @@ protected: if (!prevCont && (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) { nsIFrame* block = - aFrame->Properties().Get(nsIFrame::IBSplitPrevSibling()); + aFrame->GetProperty(nsIFrame::IBSplitPrevSibling()); if (block) { // The {ib} properties are only stored on first continuations NS_ASSERTION(!block->GetPrevContinuation(), "Incorrect value for IBSplitPrevSibling"); prevCont = - block->Properties().Get(nsIFrame::IBSplitPrevSibling()); + block->GetProperty(nsIFrame::IBSplitPrevSibling()); NS_ASSERTION(prevCont, "How did that happen?"); } } @@ -313,9 +313,9 @@ protected: (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) { // The {ib} properties are only stored on first continuations aFrame = aFrame->FirstContinuation(); - nsIFrame* block = aFrame->Properties().Get(nsIFrame::IBSplitSibling()); + nsIFrame* block = aFrame->GetProperty(nsIFrame::IBSplitSibling()); if (block) { - nextCont = block->Properties().Get(nsIFrame::IBSplitSibling()); + nextCont = block->GetProperty(nsIFrame::IBSplitSibling()); NS_ASSERTION(nextCont, "How did that happen?"); } } @@ -842,7 +842,7 @@ static nsRect GetOutlineInnerRect(nsIFrame* aFrame) { nsRect* savedOutlineInnerRect = - aFrame->Properties().Get(nsIFrame::OutlineInnerRectProperty()); + aFrame->GetProperty(nsIFrame::OutlineInnerRectProperty()); if (savedOutlineInnerRect) return *savedOutlineInnerRect; NS_NOTREACHED("we should have saved a frame property"); diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index a55ec1e39..e35e027e3 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -666,7 +666,7 @@ nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer, // EffectCompositor needs to know that we refused to run this animation // asynchronously so that it will not throttle the main thread // animation. - aFrame->Properties().Set(nsIFrame::RefusedAsyncAnimationProperty(), true); + aFrame->SetProperty(nsIFrame::RefusedAsyncAnimationProperty(), true); // We need to schedule another refresh driver run so that EffectCompositor // gets a chance to unthrottle the animation. @@ -902,15 +902,13 @@ void nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, const DisplayItemClip* oldClip = mClipState.GetClipForContainingBlockDescendants(); const DisplayItemScrollClip* sc = mClipState.GetCurrentInnermostScrollClip(); OutOfFlowDisplayData* data = new OutOfFlowDisplayData(oldClip, sc, dirty); - aFrame->Properties().Set(nsDisplayListBuilder::OutOfFlowDisplayDataProperty(), data); + aFrame->SetProperty(nsDisplayListBuilder::OutOfFlowDisplayDataProperty(), data); MarkFrameForDisplay(aFrame, aDirtyFrame); } static void UnmarkFrameForDisplay(nsIFrame* aFrame) { - nsPresContext* presContext = aFrame->PresContext(); - presContext->PropertyTable()-> - Delete(aFrame, nsDisplayListBuilder::OutOfFlowDisplayDataProperty()); + aFrame->DeleteProperty(nsDisplayListBuilder::OutOfFlowDisplayDataProperty()); for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetParentOrPlaceholderFor(f)) { diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index fcdc9e4fc..c81d34fac 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -1003,7 +1003,7 @@ public: static OutOfFlowDisplayData* GetOutOfFlowData(nsIFrame* aFrame) { - return aFrame->Properties().Get(OutOfFlowDisplayDataProperty()); + return aFrame->GetProperty(OutOfFlowDisplayDataProperty()); } nsPresContext* CurrentPresContext() { diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index 4016cc0a9..865f5534c 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -1533,11 +1533,12 @@ public: bool aFlushOnHoverChange) = 0; virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, - nsArenaMemoryStats *aArenaObjectsSize, - size_t *aPresShellSize, - size_t *aStyleSetsSize, - size_t *aTextRunsSize, - size_t *aPresContextSize) = 0; + nsArenaMemoryStats* aArenaObjectsSize, + size_t* aPresShellSize, + size_t* aStyleSetsSize, + size_t* aTextRunsSize, + size_t* aPresContextSize, + size_t* aFramePropertiesSize) = 0; /** * Methods that retrieve the cached font inflation preferences. diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 07befdc81..06690b208 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -2057,13 +2057,13 @@ NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(ScrollbarThumbLayerized, bool) /* static */ void nsLayoutUtils::SetScrollbarThumbLayerization(nsIFrame* aThumbFrame, bool aLayerize) { - aThumbFrame->Properties().Set(ScrollbarThumbLayerized(), aLayerize); + aThumbFrame->SetProperty(ScrollbarThumbLayerized(), aLayerize); } bool nsLayoutUtils::IsScrollbarThumbLayerized(nsIFrame* aThumbFrame) { - return aThumbFrame->Properties().Get(ScrollbarThumbLayerized()); + return aThumbFrame->GetProperty(ScrollbarThumbLayerized()); } // static @@ -4427,7 +4427,7 @@ nsLayoutUtils::GetNextContinuationOrIBSplitSibling(nsIFrame *aFrame) // frame in the continuation chain. Walk back to find that frame now. aFrame = aFrame->FirstContinuation(); - return aFrame->Properties().Get(nsIFrame::IBSplitSibling()); + return aFrame->GetProperty(nsIFrame::IBSplitSibling()); } return nullptr; @@ -4440,7 +4440,7 @@ nsLayoutUtils::FirstContinuationOrIBSplitSibling(nsIFrame *aFrame) if (result->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) { while (true) { nsIFrame* f = - result->Properties().Get(nsIFrame::IBSplitPrevSibling()); + result->GetProperty(nsIFrame::IBSplitPrevSibling()); if (!f) break; result = f; @@ -4456,10 +4456,10 @@ nsLayoutUtils::LastContinuationOrIBSplitSibling(nsIFrame *aFrame) nsIFrame *result = aFrame->FirstContinuation(); if (result->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) { while (true) { - nsIFrame* f = - result->Properties().Get(nsIFrame::IBSplitSibling()); - if (!f) + nsIFrame* f = result->GetProperty(nsIFrame::IBSplitSibling()); + if (!f) { break; + } result = f; } } @@ -4476,7 +4476,7 @@ nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(nsIFrame *aFrame) return false; } if ((aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) && - aFrame->Properties().Get(nsIFrame::IBSplitPrevSibling())) { + aFrame->GetProperty(nsIFrame::IBSplitPrevSibling())) { return false; } diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 3106ff386..befb5deb2 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -2741,8 +2741,7 @@ nsPresContext::GetPrimaryFrameFor(nsIContent* aContent) size_t nsPresContext::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { - return mPropertyTable.SizeOfExcludingThis(aMallocSizeOf) + - mLangGroupFontPrefs.SizeOfExcludingThis(aMallocSizeOf); + return mLangGroupFontPrefs.SizeOfExcludingThis(aMallocSizeOf); // Measurement of other members may be added later if DMD finds it is // worthwhile. diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index d8f876291..a2b9bb533 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -22,7 +22,6 @@ #include "nsITimer.h" #include "nsCRT.h" #include "nsIWidgetListener.h" -#include "FramePropertyTable.h" #include "nsGkAtoms.h" #include "nsCycleCollectionParticipant.h" #include "nsChangeHint.h" @@ -140,7 +139,6 @@ class nsRootPresContext; class nsPresContext : public nsIObserver, public mozilla::SupportsWeakPtr { public: - typedef mozilla::FramePropertyTable FramePropertyTable; typedef mozilla::LangGroupFontPrefs LangGroupFontPrefs; typedef mozilla::ScrollbarStyles ScrollbarStyles; typedef mozilla::StaticPresData StaticPresData; @@ -867,9 +865,6 @@ public: nsIPrintSettings* GetPrintSettings() { return mPrintSettings; } - /* Accessor for table of frame properties */ - FramePropertyTable* PropertyTable() { return &mPropertyTable; } - /* Helper function that ensures that this prescontext is shown in its docshell if it's the most recent prescontext for the docshell. Returns whether the prescontext is now being shown. @@ -1064,11 +1059,6 @@ public: */ nsIFrame* GetPrimaryFrameFor(nsIContent* aContent); - void NotifyDestroyingFrame(nsIFrame* aFrame) - { - PropertyTable()->DeleteAllFor(aFrame); - } - virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); @@ -1294,7 +1284,6 @@ protected: nsCOMPtr mPrintSettings; nsCOMPtr mPrefChangedTimer; - FramePropertyTable mPropertyTable; nsInvalidateRequestList mInvalidateRequestsSinceLastPaint; nsInvalidateRequestList mUndeliveredInvalidateRequestsBeforeLastPaint; diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index d4fbebbf2..dacc6603b 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1306,19 +1306,6 @@ PresShell::Destroy() // Destroy the frame manager. This will destroy the frame hierarchy mFrameConstructor->WillDestroyFrameTree(); - // Destroy all frame properties (whose destruction was suppressed - // while destroying the frame tree, but which might contain more - // frames within the properties. - if (mPresContext) { - // Clear out the prescontext's property table -- since our frame tree is - // now dead, we shouldn't be looking up any more properties in that table. - // We want to do this before we call DetachShell() on the prescontext, so - // property destructors can usefully call GetPresShell() on the - // prescontext. - mPresContext->PropertyTable()->DeleteAll(); - } - - NS_WARNING_ASSERTION(!mWeakFrames, "Weak frames alive after destroying FrameManager"); while (mWeakFrames) { @@ -2047,7 +2034,7 @@ PresShell::NotifyDestroyingFrame(nsIFrame* aFrame) } // Remove frame properties - mPresContext->NotifyDestroyingFrame(aFrame); + aFrame->DeleteAllProperties(); if (aFrame == mCurrentEventFrame) { mCurrentEventContent = aFrame->GetContent(); @@ -2076,8 +2063,7 @@ PresShell::NotifyDestroyingFrame(nsIFrame* aFrame) // frame from FrameLayerBuilder::DisplayItemData::mFrameList -- otherwise // the DisplayItemData destructor will use the destroyed frame when it // tries to remove it from the (array) value of this property. - mPresContext->PropertyTable()-> - Delete(aFrame, FrameLayerBuilder::LayerManagerDataProperty()); + aFrame->DeleteProperty( FrameLayerBuilder::LayerManagerDataProperty()); } } @@ -10929,11 +10915,12 @@ PresShell::GetRootPresShell() void PresShell::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, - nsArenaMemoryStats *aArenaObjectsSize, - size_t *aPresShellSize, - size_t *aStyleSetsSize, - size_t *aTextRunsSize, - size_t *aPresContextSize) + nsArenaMemoryStats* aArenaObjectsSize, + size_t* aPresShellSize, + size_t* aStyleSetsSize, + size_t* aTextRunsSize, + size_t* aPresContextSize, + size_t* aFramePropertiesSize) { mFrameArena.AddSizeOfExcludingThis(aMallocSizeOf, aArenaObjectsSize); *aPresShellSize += aMallocSizeOf(this); @@ -10953,6 +10940,12 @@ PresShell::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, *aTextRunsSize += SizeOfTextRuns(aMallocSizeOf); *aPresContextSize += mPresContext->SizeOfIncludingThis(aMallocSizeOf); + + nsIFrame* rootFrame = mFrameConstructor->GetRootFrame(); + if (rootFrame) { + *aFramePropertiesSize += + rootFrame->SizeOfFramePropertiesForTree(aMallocSizeOf); + } } size_t diff --git a/layout/base/nsPresShell.h b/layout/base/nsPresShell.h index 1a8dd3fef..10548880a 100644 --- a/layout/base/nsPresShell.h +++ b/layout/base/nsPresShell.h @@ -384,11 +384,12 @@ public: virtual void LoadComplete() override; void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, - nsArenaMemoryStats *aArenaObjectsSize, - size_t *aPresShellSize, - size_t *aStyleSetsSize, - size_t *aTextRunsSize, - size_t *aPresContextSize) override; + nsArenaMemoryStats* aArenaObjectsSize, + size_t* aPresShellSize, + size_t* aStyleSetsSize, + size_t* aTextRunsSize, + size_t* aPresContextSize, + size_t* aFramePropertiesSize) override; size_t SizeOfTextRuns(mozilla::MallocSizeOf aMallocSizeOf) const; virtual void AddInvalidateHiddenPresShellObserver(nsRefreshDriver *aDriver) override; -- cgit v1.2.3