diff options
Diffstat (limited to 'layout/base')
-rw-r--r-- | layout/base/ActiveLayerTracker.cpp | 15 | ||||
-rw-r--r-- | layout/base/FrameLayerBuilder.cpp | 41 | ||||
-rw-r--r-- | layout/base/FrameProperties.h (renamed from layout/base/FramePropertyTable.h) | 298 | ||||
-rw-r--r-- | layout/base/FramePropertyTable.cpp | 239 | ||||
-rw-r--r-- | layout/base/OverflowChangedTracker.h | 4 | ||||
-rw-r--r-- | layout/base/RestyleManager.cpp | 10 | ||||
-rw-r--r-- | layout/base/RestyleManagerBase.cpp | 88 | ||||
-rw-r--r-- | layout/base/RestyleManagerBase.h | 13 | ||||
-rw-r--r-- | layout/base/moz.build | 3 | ||||
-rw-r--r-- | layout/base/nsBidiPresUtils.cpp | 5 | ||||
-rw-r--r-- | layout/base/nsCSSFrameConstructor.cpp | 23 | ||||
-rw-r--r-- | layout/base/nsCSSRendering.cpp | 10 | ||||
-rw-r--r-- | layout/base/nsDisplayList.cpp | 49 | ||||
-rw-r--r-- | layout/base/nsDisplayList.h | 2 | ||||
-rw-r--r-- | layout/base/nsIPresShell.h | 11 | ||||
-rw-r--r-- | layout/base/nsLayoutUtils.cpp | 16 | ||||
-rw-r--r-- | layout/base/nsPresContext.cpp | 3 | ||||
-rw-r--r-- | layout/base/nsPresContext.h | 11 | ||||
-rw-r--r-- | layout/base/nsPresShell.cpp | 35 | ||||
-rw-r--r-- | layout/base/nsPresShell.h | 11 |
20 files changed, 344 insertions, 543 deletions
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..934d108e0 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -165,10 +165,10 @@ FrameLayerBuilder::DisplayItemData::AddFrame(nsIFrame* aFrame) mFrameList.AppendElement(aFrame); nsTArray<DisplayItemData*>* array = - aFrame->Properties().Get(FrameLayerBuilder::LayerManagerDataProperty()); + aFrame->GetProperty(FrameLayerBuilder::LayerManagerDataProperty()); if (!array) { array = new nsTArray<DisplayItemData*>(); - 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<DisplayItemData*>* 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,12 +268,17 @@ FrameLayerBuilder::DisplayItemData::~DisplayItemData() continue; } nsTArray<DisplayItemData*> *array = - reinterpret_cast<nsTArray<DisplayItemData*>*>(frame->Properties().Get(LayerManagerDataProperty())); + reinterpret_cast<nsTArray<DisplayItemData*>*>(frame->GetProperty(LayerManagerDataProperty())); array->RemoveElement(this); } - MOZ_RELEASE_ASSERT(sAliveDisplayItemDatas && sAliveDisplayItemDatas->Contains(this)); - sAliveDisplayItemDatas->RemoveEntry(this); + MOZ_RELEASE_ASSERT(sAliveDisplayItemDatas); + nsPtrHashKey<mozilla::FrameLayerBuilder::DisplayItemData>* entry + = sAliveDisplayItemDatas->GetEntry(this); + MOZ_RELEASE_ASSERT(entry); + + sAliveDisplayItemDatas->RemoveEntry(entry); + if (sAliveDisplayItemDatas->Count() == 0) { delete sAliveDisplayItemDatas; sAliveDisplayItemDatas = nullptr; @@ -390,8 +395,7 @@ public: /* static */ void FrameLayerBuilder::DestroyDisplayItemDataFor(nsIFrame* aFrame) { - FrameProperties props = aFrame->Properties(); - props.Delete(LayerManagerDataProperty()); + aFrame->DeleteProperty(LayerManagerDataProperty()); } struct AssignedDisplayItem @@ -1823,7 +1827,7 @@ FrameLayerBuilder::DisplayItemData* FrameLayerBuilder::GetDisplayItemData(nsIFrame* aFrame, uint32_t aKey) { const nsTArray<DisplayItemData*>* 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 +2056,7 @@ FrameLayerBuilder::GetDisplayItemDataForManager(nsDisplayItem* aItem, LayerManager* aManager) { const nsTArray<DisplayItemData*>* 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 +2073,7 @@ bool FrameLayerBuilder::HasRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey) { const nsTArray<DisplayItemData*>* 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 +2088,7 @@ void FrameLayerBuilder::IterateRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallback aCallback) { const nsTArray<DisplayItemData*>* array = - aFrame->Properties().Get(LayerManagerDataProperty()); + aFrame->GetProperty(LayerManagerDataProperty()); if (!array) { return; } @@ -2151,7 +2155,7 @@ FrameLayerBuilder::ClearCachedGeometry(nsDisplayItem* aItem) FrameLayerBuilder::GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey) { const nsTArray<DisplayItemData*>* array = - aFrame->Properties().Get(LayerManagerDataProperty()); + aFrame->GetProperty(LayerManagerDataProperty()); if (!array) { return nullptr; @@ -2171,7 +2175,7 @@ FrameLayerBuilder::GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKe FrameLayerBuilder::GetDebugSingleOldPaintedLayerForFrame(nsIFrame* aFrame) { const nsTArray<DisplayItemData*>* array = - aFrame->Properties().Get(LayerManagerDataProperty()); + aFrame->GetProperty(LayerManagerDataProperty()); if (!array) { return nullptr; @@ -5656,7 +5660,7 @@ FrameLayerBuilder::InvalidateAllLayers(LayerManager* aManager) FrameLayerBuilder::InvalidateAllLayersForFrame(nsIFrame *aFrame) { const nsTArray<DisplayItemData*>* 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 +5677,7 @@ FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, uint32_t aDisplayItemKey) // in the secondary manager const nsTArray<DisplayItemData*>* 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 +5733,7 @@ FrameLayerBuilder::GetPaintedLayerScaleForFrame(nsIFrame* aFrame) } const nsTArray<DisplayItemData*>* array = - f->Properties().Get(LayerManagerDataProperty()); + f->GetProperty(LayerManagerDataProperty()); if (!array) { continue; } @@ -6165,9 +6169,8 @@ FrameLayerBuilder::GetMostRecentGeometry(nsDisplayItem* aItem) typedef nsTArray<DisplayItemData*> 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/FramePropertyTable.h b/layout/base/FrameProperties.h index e9847efbf..3884b07bd 100644 --- a/layout/base/FramePropertyTable.h +++ b/layout/base/FrameProperties.h @@ -3,15 +3,15 @@ * 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_ +#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 "nsTHashtable.h" -#include "nsHashKeys.h" +#include "nsThreadUtils.h" class nsIFrame; @@ -62,7 +62,7 @@ protected: * * 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. + * aProperty in the FrameProperties methods. */ template<typename T> struct FramePropertyDescriptor : public FramePropertyDescriptorUntyped @@ -131,7 +131,7 @@ struct FramePropertyTypeHelper<SmallValueHolder<T>> } /** - * The FramePropertyTable is optimized for storing 0 or 1 properties on + * 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. * @@ -141,7 +141,8 @@ struct FramePropertyTypeHelper<SmallValueHolder<T>> * Of course, the destructor function (if any) must handle such values * correctly. */ -class FramePropertyTable { +class FrameProperties +{ public: template<typename T> using Descriptor = const FramePropertyDescriptor<T>*; @@ -150,32 +151,36 @@ public: template<typename T> using PropertyType = typename detail::FramePropertyTypeHelper<T>::Type; - FramePropertyTable() : mLastFrame(nullptr), mLastEntry(nullptr) + explicit FrameProperties() { } - ~FramePropertyTable() + + ~FrameProperties() { - DeleteAll(); + MOZ_ASSERT(mProperties.Length() == 0, "forgot to delete properties"); } /** - * 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 + * Return true if we have no properties, otherwise return false. + */ + bool IsEmpty() const { return mProperties.IsEmpty(); } + + /** + * Set a property value. This requires a linear search through + * the properties of the frame. Any existing value for the property * is destroyed. */ template<typename T> - void Set(const nsIFrame* aFrame, Descriptor<T> aProperty, - PropertyType<T> aValue) + void Set(Descriptor<T> aProperty, PropertyType<T> aValue, + const nsIFrame* aFrame) { void* ptr = ReinterpretHelper<T>::ToPointer(aValue); - SetInternal(aFrame, aProperty, ptr); + SetInternal(aProperty, ptr, aFrame); } /** - * @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. + * @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() @@ -190,17 +195,14 @@ public: * an existing value for the frame property. */ template<typename T> - bool Has(const nsIFrame* aFrame, Descriptor<T> aProperty) + bool Has(Descriptor<T> aProperty) const { - bool foundResult = false; - mozilla::Unused << GetInternal(aFrame, aProperty, &foundResult); - return foundResult; + return mProperties.IndexOf(aProperty, 0, PropertyComparator()) != nsTArray<PropertyValue>::NoIndex; } /** - * 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, + * Get a property value. This requires 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 @@ -209,16 +211,15 @@ public: * 'property value is null'. */ template<typename T> - PropertyType<T> Get(const nsIFrame* aFrame, Descriptor<T> aProperty, - bool* aFoundResult = nullptr) + PropertyType<T> Get(Descriptor<T> aProperty, + bool* aFoundResult = nullptr) const { - void* ptr = GetInternal(aFrame, aProperty, aFoundResult); + void* ptr = GetInternal(aProperty, aFoundResult); return ReinterpretHelper<T>::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 + * 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. @@ -228,46 +229,85 @@ public: * 'property value is null'. */ template<typename T> - PropertyType<T> Remove(const nsIFrame* aFrame, Descriptor<T> aProperty, + PropertyType<T> Remove(Descriptor<T> aProperty, bool* aFoundResult = nullptr) { - void* ptr = RemoveInternal(aFrame, aProperty, aFoundResult); + void* ptr = RemoveInternal(aProperty, aFoundResult); return ReinterpretHelper<T>::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 + * 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<typename T> - void Delete(const nsIFrame* aFrame, Descriptor<T> aProperty) + void Delete(Descriptor<T> aProperty, const nsIFrame* aFrame) { - DeleteInternal(aFrame, aProperty); + DeleteInternal(aProperty, aFrame); } + /** - * Remove and destroy all property values for a frame. This requires one - * hashtable lookup (using the frame as the key). + * Call @aFunction for each property or until @aFunction returns false. */ - void DeleteAllFor(const nsIFrame* aFrame); + template<class F> + void ForEach(F aFunction) const + { +#ifdef DEBUG + size_t len = mProperties.Length(); +#endif + for (const auto& prop : mProperties) { + bool shouldContinue = aFunction(prop.mProperty, prop.mValue); +#ifdef DEBUG + MOZ_ASSERT(len == mProperties.Length(), + "frame property list was modified by ForEach callback!"); +#endif + if (!shouldContinue) { + return; + } + } + } + /** - * Remove and destroy all property values for all frames. + * Remove and destroy all property values for the frame. */ - void DeleteAll(); + void DeleteAll(const nsIFrame* aFrame) { + mozilla::DebugOnly<size_t> len = mProperties.Length(); + for (auto& prop : mProperties) { + prop.DestroyValueFor(aFrame); + MOZ_ASSERT(mProperties.Length() == len); + } + mProperties.Clear(); + } - size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + 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); + } -protected: - void SetInternal(const nsIFrame* aFrame, UntypedDescriptor aProperty, - void* aValue); +private: + friend class ::nsIFrame; - void* GetInternal(const nsIFrame* aFrame, UntypedDescriptor aProperty, - bool* aFoundResult); + // Prevent copying of FrameProperties; we should always return/pass around + // references to it, not copies! + FrameProperties(const FrameProperties&) = delete; + FrameProperties& operator=(const FrameProperties&) = delete; - void* RemoveInternal(const nsIFrame* aFrame, UntypedDescriptor aProperty, - bool* aFoundResult); + inline void + SetInternal(UntypedDescriptor aProperty, void* aValue, + const nsIFrame* aFrame); - void DeleteInternal(const nsIFrame* aFrame, UntypedDescriptor aProperty); + inline void* + GetInternal(UntypedDescriptor aProperty, bool* aFoundResult) const; + + inline void* + RemoveInternal(UntypedDescriptor aProperty, bool* aFoundResult); + + inline void + DeleteInternal(UntypedDescriptor aProperty, const nsIFrame* aFrame); template<typename T> struct ReinterpretHelper @@ -305,21 +345,13 @@ protected: }; /** - * Stores a property descriptor/value pair. It can also be used to - * store an nsTArray of PropertyValues. + * Stores a property descriptor/value pair. */ struct PropertyValue { PropertyValue() : mProperty(nullptr), mValue(nullptr) {} PropertyValue(UntypedDescriptor aProperty, void* aValue) : mProperty(aProperty), mValue(aValue) {} - bool IsArray() { return !mProperty && mValue; } - nsTArray<PropertyValue>* ToArray() - { - NS_ASSERTION(IsArray(), "Must be array"); - return reinterpret_cast<nsTArray<PropertyValue>*>(&mValue); - } - void DestroyValueFor(const nsIFrame* aFrame) { if (mProperty->mDestructor) { mProperty->mDestructor(mValue); @@ -328,20 +360,6 @@ protected: } } - 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<PropertyValue>* array = ToArray(); - n += array->ShallowSizeOfExcludingThis(aMallocSizeOf); - } - return n; - } - UntypedDescriptor mProperty; void* mValue; }; @@ -363,80 +381,86 @@ protected: } }; - /** - * Our hashtable entry. The key is an nsIFrame*, the value is a - * PropertyValue representing one or more property/value pairs. - */ - class Entry : public nsPtrHashKey<const nsIFrame> - { - public: - explicit Entry(KeyTypePointer aKey) : nsPtrHashKey<const nsIFrame>(aKey) {} - Entry(const Entry &toCopy) : - nsPtrHashKey<const nsIFrame>(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<Entry> mEntries; - const nsIFrame* mLastFrame; - Entry* mLastEntry; + nsTArray<PropertyValue> mProperties; }; /** * This class encapsulates the properties of a frame. */ -class FrameProperties { -public: - template<typename T> using Descriptor = FramePropertyTable::Descriptor<T>; - template<typename T> using PropertyType = FramePropertyTable::PropertyType<T>; - - FrameProperties(FramePropertyTable* aTable, const nsIFrame* aFrame) - : mTable(aTable), mFrame(aFrame) {} +inline void* +FrameProperties::GetInternal(UntypedDescriptor aProperty, + bool* aFoundResult) const +{ + MOZ_ASSERT(aProperty, "Null property?"); - template<typename T> - void Set(Descriptor<T> aProperty, PropertyType<T> aValue) const - { - mTable->Set(mFrame, aProperty, aValue); + auto index = mProperties.IndexOf(aProperty, 0, PropertyComparator()); + if (index == nsTArray<PropertyValue>::NoIndex) { + if (aFoundResult) { + *aFoundResult = false; + } + return nullptr; } - template<typename T> - bool Has(Descriptor<T> aProperty) const - { - return mTable->Has(mFrame, aProperty); + if (aFoundResult) { + *aFoundResult = true; } - template<typename T> - PropertyType<T> Get(Descriptor<T> aProperty, - bool* aFoundResult = nullptr) const - { - return mTable->Get(mFrame, aProperty, aFoundResult); - } - template<typename T> - PropertyType<T> Remove(Descriptor<T> aProperty, - bool* aFoundResult = nullptr) const - { - return mTable->Remove(mFrame, aProperty, aFoundResult); +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<PropertyValue>::NoIndex) { + PropertyValue* pv = &mProperties.ElementAt(index); + pv->DestroyValueFor(aFrame); + pv->mValue = aValue; + return; } - template<typename T> - void Delete(Descriptor<T> aProperty) - { - mTable->Delete(mFrame, aProperty); + + 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<PropertyValue>::NoIndex) { + if (aFoundResult) { + *aFoundResult = false; + } + return nullptr; } -private: - FramePropertyTable* mTable; - const nsIFrame* mFrame; -}; +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<PropertyValue>::NoIndex) { + mProperties.ElementAt(index).DestroyValueFor(aFrame); + mProperties.RemoveElementAt(index); + } +} } // namespace mozilla -#endif /* FRAMEPROPERTYTABLE_H_ */ +#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<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 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<nsIContent*> 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<nsIFrame*> - (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<nsTHashtable<nsPtrHashKey<const nsIFrame>>>(); +} 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<nsTHashtable<nsPtrHashKey<const nsIFrame>>> 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<nsContainerFrame*> - (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<nsContainerFrame*> - (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..e22230b41 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)) { @@ -5710,7 +5708,7 @@ nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame, } /* Allows us to access dimension getters by index. */ - float coords[2]; + float transformOrigin[2]; TransformReferenceBox::DimensionGetter dimensionGetter[] = { &TransformReferenceBox::Width, &TransformReferenceBox::Height }; TransformReferenceBox::DimensionGetter offsetGetter[] = @@ -5720,33 +5718,33 @@ nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame, /* If the transform-origin specifies a percentage, take the percentage * of the size of the box. */ - const nsStyleCoord &coord = display->mTransformOrigin[index]; - if (coord.GetUnit() == eStyleUnit_Calc) { - const nsStyleCoord::Calc *calc = coord.GetCalcValue(); - coords[index] = + const nsStyleCoord &originValue = display->mTransformOrigin[index]; + if (originValue.GetUnit() == eStyleUnit_Calc) { + const nsStyleCoord::Calc *calc = originValue.GetCalcValue(); + transformOrigin[index] = NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) * calc->mPercent + NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel); - } else if (coord.GetUnit() == eStyleUnit_Percent) { - coords[index] = + } else if (originValue.GetUnit() == eStyleUnit_Percent) { + transformOrigin[index] = NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) * - coord.GetPercentValue(); + originValue.GetPercentValue(); } else { - MOZ_ASSERT(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit"); - coords[index] = - NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel); + MOZ_ASSERT(originValue.GetUnit() == eStyleUnit_Coord, "unexpected unit"); + transformOrigin[index] = + NSAppUnitsToFloatPixels(originValue.GetCoordValue(), aAppUnitsPerPixel); } if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) { // SVG frames (unlike other frames) have a reference box that can be (and // typically is) offset from the TopLeft() of the frame. We need to // account for that here. - coords[index] += + transformOrigin[index] += NSAppUnitsToFloatPixels((refBox.*offsetGetter[index])(), aAppUnitsPerPixel); } } - return Point3D(coords[0], coords[1], + return Point3D(transformOrigin[0], transformOrigin[1], NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(), aAppUnitsPerPixel)); } @@ -5919,6 +5917,17 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp frame && frame->IsSVGTransformed(&svgTransform, &transformFromSVGParent); bool hasTransformFromSVGParent = hasSVGTransforms && !transformFromSVGParent.IsIdentity(); + + bool shouldRound = true; + + // An SVG frame should not have its translation rounded. + // Note it's possible that the SVG frame doesn't have an SVG + // transform but only has a CSS transform. + if (frame && frame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT) && + !(frame->GetType() == nsGkAtoms::svgOuterSVGAnonChildFrame)) { + shouldRound = false; + } + /* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */ if (aProperties.mTransformList) { result = nsStyleTransformMatrix::ReadTransforms(aProperties.mTransformList->mHead, @@ -5996,7 +6005,7 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp // Otherwise we need to manually translate into our parent's coordinate // space. if (frame->IsTransformed()) { - nsLayoutUtils::PostTranslate(result, frame->GetPosition(), aAppUnitsPerPixel, !hasSVGTransforms); + nsLayoutUtils::PostTranslate(result, frame->GetPosition(), aAppUnitsPerPixel, shouldRound); } Matrix4x4 parent = GetResultingTransformMatrixInternal(props, @@ -6007,7 +6016,7 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp } if (aFlags & OFFSET_BY_ORIGIN) { - nsLayoutUtils::PostTranslate(result, aOrigin, aAppUnitsPerPixel, !hasSVGTransforms); + nsLayoutUtils::PostTranslate(result, aOrigin, aAppUnitsPerPixel, shouldRound); } return result; 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<nsPresContext> { 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<nsIPrintSettings> mPrintSettings; nsCOMPtr<nsITimer> mPrefChangedTimer; - FramePropertyTable mPropertyTable; nsInvalidateRequestList mInvalidateRequestsSinceLastPaint; nsInvalidateRequestList mUndeliveredInvalidateRequestsBeforeLastPaint; diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 5dfbb8dba..264b52b18 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()); } } @@ -10917,11 +10903,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); @@ -10941,6 +10928,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 7a9056a38..f20370d73 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; |