Browse Source

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.
pull/7/head
win7-7 3 years ago committed by Roy Tam
parent
commit
922e819d1c
  1. 3
      dom/base/nsDocument.cpp
  2. 9
      dom/base/nsWindowMemoryReporter.cpp
  3. 1
      dom/base/nsWindowMemoryReporter.h
  4. 15
      layout/base/ActiveLayerTracker.cpp
  5. 32
      layout/base/FrameLayerBuilder.cpp
  6. 272
      layout/base/FrameProperties.h
  7. 239
      layout/base/FramePropertyTable.cpp
  8. 4
      layout/base/OverflowChangedTracker.h
  9. 10
      layout/base/RestyleManager.cpp
  10. 88
      layout/base/RestyleManagerBase.cpp
  11. 13
      layout/base/RestyleManagerBase.h
  12. 3
      layout/base/moz.build
  13. 5
      layout/base/nsBidiPresUtils.cpp
  14. 23
      layout/base/nsCSSFrameConstructor.cpp
  15. 10
      layout/base/nsCSSRendering.cpp
  16. 8
      layout/base/nsDisplayList.cpp
  17. 2
      layout/base/nsDisplayList.h
  18. 11
      layout/base/nsIPresShell.h
  19. 16
      layout/base/nsLayoutUtils.cpp
  20. 3
      layout/base/nsPresContext.cpp
  21. 11
      layout/base/nsPresContext.h
  22. 35
      layout/base/nsPresShell.cpp
  23. 11
      layout/base/nsPresShell.h
  24. 14
      layout/forms/nsTextControlFrame.cpp
  25. 2
      layout/forms/nsTextControlFrame.h
  26. 36
      layout/generic/ReflowInput.cpp
  27. 6
      layout/generic/RubyUtils.cpp
  28. 26
      layout/generic/StickyScrollContainer.cpp
  29. 58
      layout/generic/nsBlockFrame.cpp
  30. 4
      layout/generic/nsBlockFrame.h
  31. 6
      layout/generic/nsBulletFrame.cpp
  32. 4
      layout/generic/nsCanvasFrame.cpp
  33. 2
      layout/generic/nsCanvasFrame.h
  34. 70
      layout/generic/nsContainerFrame.cpp
  35. 10
      layout/generic/nsContainerFrame.h
  36. 22
      layout/generic/nsFlexContainerFrame.cpp
  37. 9
      layout/generic/nsFloatManager.cpp
  38. 12
      layout/generic/nsFontInflationData.cpp
  39. 177
      layout/generic/nsFrame.cpp
  40. 80
      layout/generic/nsGridContainerFrame.cpp
  41. 12
      layout/generic/nsGridContainerFrame.h
  42. 75
      layout/generic/nsIFrame.h
  43. 4
      layout/generic/nsLineLayout.cpp
  44. 2
      layout/generic/nsPlaceholderFrame.cpp
  45. 59
      layout/generic/nsTextFrame.cpp
  46. 7
      layout/mathml/nsMathMLContainerFrame.cpp
  47. 14
      layout/mathml/nsMathMLmtableFrame.cpp
  48. 10
      layout/svg/SVGTextFrame.cpp
  49. 47
      layout/svg/nsSVGEffects.cpp
  50. 2
      layout/svg/nsSVGEffects.h
  51. 4
      layout/svg/nsSVGFilterFrame.cpp
  52. 4
      layout/svg/nsSVGGradientFrame.cpp
  53. 5
      layout/svg/nsSVGIntegrationUtils.cpp
  54. 4
      layout/svg/nsSVGPatternFrame.cpp
  55. 5
      layout/svg/nsSVGUtils.cpp
  56. 31
      layout/tables/nsTableFrame.cpp
  57. 3
      layout/tables/nsTableFrame.h
  58. 10
      layout/tables/nsTableRowFrame.cpp
  59. 6
      layout/tables/nsTableRowGroupFrame.cpp
  60. 4
      layout/tables/nsTableWrapperFrame.cpp
  61. 7
      layout/xul/nsBox.cpp
  62. 6
      layout/xul/nsMenuFrame.cpp

3
dom/base/nsDocument.cpp

@ -11943,7 +11943,8 @@ nsIDocument::DocAddSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const
&aWindowSizes->mLayoutPresShellSize,
&aWindowSizes->mLayoutStyleSetsSize,
&aWindowSizes->mLayoutTextRunsSize,
&aWindowSizes->mLayoutPresContextSize);
&aWindowSizes->mLayoutPresContextSize,
&aWindowSizes->mLayoutFramePropertiesSize);
}
aWindowSizes->mPropertyTablesSize +=

9
dom/base/nsWindowMemoryReporter.cpp

@ -400,6 +400,12 @@ CollectWindowReports(nsGlobalWindow *aWindow,
aWindowTotalSizes->mLayoutPresContextSize +=
windowSizes.mLayoutPresContextSize;
REPORT_SIZE("/layout/frame-properties", windowSizes.mLayoutFramePropertiesSize,
"Memory used for frame properties attached to frames "
"within a window.");
aWindowTotalSizes->mLayoutFramePropertiesSize +=
windowSizes.mLayoutFramePropertiesSize;
// There are many different kinds of frames, but it is very likely
// that only a few matter. Implement a cutoff so we don't bloat
// about:memory with many uninteresting entries.
@ -563,6 +569,9 @@ nsWindowMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
REPORT("window-objects/layout/pres-contexts", windowTotalSizes.mLayoutPresContextSize,
"This is the sum of all windows' 'layout/pres-contexts' numbers.");
REPORT("window-objects/layout/frame-properties", windowTotalSizes.mLayoutFramePropertiesSize,
"This is the sum of all windows' 'layout/frame-properties' numbers.");
size_t frameTotal = 0;
#define FRAME_ID(classname) \
frameTotal += windowTotalSizes.mArenaStats.FRAME_ID_STAT_FIELD(classname);

1
dom/base/nsWindowMemoryReporter.h

@ -33,6 +33,7 @@ class nsWindowSizes {
macro(Style, mLayoutStyleSetsSize) \
macro(Other, mLayoutTextRunsSize) \
macro(Other, mLayoutPresContextSize) \
macro(Other, mLayoutFramePropertiesSize) \
macro(Other, mPropertyTablesSize) \
public:

15
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

32
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,7 +268,7 @@ 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);
}
@ -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<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 +2051,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 +2068,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 +2083,7 @@ void
FrameLayerBuilder::IterateRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallback aCallback)
{
const nsTArray<DisplayItemData*>* 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<DisplayItemData*>* 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<DisplayItemData*>* 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<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 +5672,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 +5728,7 @@ FrameLayerBuilder::GetPaintedLayerScaleForFrame(nsIFrame* aFrame)
}
const nsTArray<DisplayItemData*>* array =
f->Properties().Get(LayerManagerDataProperty());
f->GetProperty(LayerManagerDataProperty());
if (!array) {
continue;
}
@ -6165,9 +6164,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;
}

272
layout/base/FramePropertyTable.h → 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;
@ -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,31 @@ 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
* 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 +190,15 @@ 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
* 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 that frame. If the frame has no such property,
* 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 +207,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 +225,63 @@ 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).
*/
void DeleteAllFor(const nsIFrame* aFrame);
/**
* 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;
// 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* GetInternal(const nsIFrame* aFrame, UntypedDescriptor aProperty,
bool* aFoundResult);
inline void
SetInternal(UntypedDescriptor aProperty, void* aValue,
const nsIFrame* aFrame);
void* RemoveInternal(const nsIFrame* aFrame, UntypedDescriptor aProperty,
bool* aFoundResult);
inline void*
GetInternal(UntypedDescriptor aProperty, bool* aFoundResult) const;
void DeleteInternal(const nsIFrame* aFrame, UntypedDescriptor aProperty);
inline void*
RemoveInternal(UntypedDescriptor aProperty, bool* aFoundResult);
inline void
DeleteInternal(UntypedDescriptor aProperty, const nsIFrame* aFrame);
template<typename T>
struct ReinterpretHelper
@ -305,21 +319,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 +334,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 +355,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_ */

239
layout/base/FramePropertyTable.cpp

@ -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

4
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.

10
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

88
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;

13
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

3
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',

5
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();

23
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()-