Bug 1331718 - Part 3: Store pointers to DisplayItemData directly on nsIFrame. r=mattwoodrow r=dbaron
This patch aims to speed up the lookup and storage of DisplayItemData objects, by removing a level of indirection and preventing the previously required hashtable lookup in order to access these. Instead it stores an array of pointers on each frame that allows direct access to the DisplayItemData object by dereferencing the frame. Since most frames get either 1 or 2 DisplayItemData objects attached to them a specialized class is used that is of minimal size (2 * sizeof(void)) and that performs well for sizes 1 or 2.
MozReview-Commit-ID: Hp5aHO1wlh7
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -2068,16 +2068,22 @@ PresShell::SetIgnoreFrameDestruction(boo
mDocument->StyleImageLoader()->ClearFrames(mPresContext);
}
mIgnoreFrameDestruction = aIgnore;
}
void
PresShell::NotifyDestroyingFrame(nsIFrame* aFrame)
{
+ // We must remove these from FrameLayerBuilder::DisplayItemData::mFrameList here,
+ // otherwise the DisplayItemData destructor will use the destroyed frame when it
+ // tries to remove it from the (array) value of this property.
+ FrameLayerBuilder::RemoveFrameFromLayerManager(aFrame, aFrame->DisplayItemData());
+ aFrame->DisplayItemData().Clear();
+
if (!mIgnoreFrameDestruction) {
mDocument->StyleImageLoader()->DropRequestsForFrame(aFrame);
mFrameConstructor->NotifyDestroyingFrame(aFrame);
for (int32_t idx = mDirtyRoots.Length(); idx; ) {
--idx;
if (mDirtyRoots[idx] == aFrame) {
@@ -2105,23 +2111,16 @@ PresShell::NotifyDestroyingFrame(nsIFram
//pop it we can still get its new frame from its content
nsIContent *currentEventContent = aFrame->GetContent();
mCurrentEventContentStack.ReplaceObjectAt(currentEventContent, i);
mCurrentEventFrameStack[i] = nullptr;
}
}
mFramesToDirty.RemoveEntry(aFrame);
- } else {
- // We must delete this property in situ so that its destructor removes the
- // 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());
}
}
already_AddRefed<nsCaret> PresShell::GetCaret() const
{
RefPtr<nsCaret> caret = mCaret;
return caret.forget();
}
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -22,16 +22,17 @@
#include <algorithm>
#include <stdio.h>
#include "CaretAssociationHint.h"
#include "FramePropertyTable.h"
#include "mozilla/layout/FrameChildList.h"
#include "mozilla/Maybe.h"
+#include "mozilla/SmallPointerArray.h"
#include "mozilla/WritingModes.h"
#include "nsDirection.h"
#include "nsFrameList.h"
#include "nsFrameState.h"
#include "mozilla/ReflowOutput.h"
#include "nsITheme.h"
#include "nsLayoutUtils.h"
#include "nsQueryFrame.h"
@@ -93,16 +94,17 @@ struct CharacterDataChangeInfo;
namespace mozilla {
enum class CSSPseudoElementType : uint8_t;
class EventStates;
struct ReflowInput;
class ReflowOutput;
class ServoStyleSet;
+class DisplayItemData;
namespace layers {
class Layer;
} // namespace layers
namespace gfx {
class Matrix;
} // namespace gfx
@@ -584,16 +586,17 @@ public:
typedef mozilla::layout::FrameChildListIDs ChildListIDs;
typedef mozilla::layout::FrameChildListIterator ChildListIterator;
typedef mozilla::layout::FrameChildListArrayIterator ChildListArrayIterator;
typedef mozilla::gfx::DrawTarget DrawTarget;
typedef mozilla::gfx::Matrix Matrix;
typedef mozilla::gfx::Matrix4x4 Matrix4x4;
typedef mozilla::Sides Sides;
typedef mozilla::LogicalSides LogicalSides;
+ typedef mozilla::SmallPointerArray<mozilla::DisplayItemData> DisplayItemArray;
NS_DECL_QUERYFRAME_TARGET(nsIFrame)
nsIFrame()
: mRect()
, mContent(nullptr)
, mStyleContext(nullptr)
, mParent(nullptr)
@@ -3689,32 +3692,37 @@ public:
* Helper function - computes the content-box inline size for aCoord.
*/
nscoord ComputeISizeValue(nsRenderingContext* aRenderingContext,
nscoord aContainingBlockISize,
nscoord aContentEdgeToBoxSizing,
nscoord aBoxSizingToMarginEdge,
const nsStyleCoord& aCoord,
ComputeSizeFlags aFlags = eDefault);
+
+ DisplayItemArray& DisplayItemData() { return mDisplayItemData; }
+
protected:
+
/**
* Reparent this frame's view if it has one.
*/
void ReparentFrameViewTo(nsViewManager* aViewManager,
nsView* aNewParentView,
nsView* aOldParentView);
// Members
nsRect mRect;
nsIContent* mContent;
nsStyleContext* mStyleContext;
private:
nsContainerFrame* mParent;
nsIFrame* mNextSibling; // doubly-linked list of frames
nsIFrame* mPrevSibling; // Do not touch outside SetNextSibling!
+ DisplayItemArray mDisplayItemData;
void MarkAbsoluteFramesForDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect);
static void DestroyPaintedPresShellList(nsTArray<nsWeakPtr>* list) {
list->Clear();
delete list;
}
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -160,36 +160,29 @@ DisplayItemData::DisplayItemData(LayerMa
}
void
DisplayItemData::AddFrame(nsIFrame* aFrame)
{
MOZ_RELEASE_ASSERT(mLayer);
mFrameList.AppendElement(aFrame);
- nsTArray<DisplayItemData*>* array =
- aFrame->Properties().Get(FrameLayerBuilder::LayerManagerDataProperty());
- if (!array) {
- array = new nsTArray<DisplayItemData*>();
- aFrame->Properties().Set(FrameLayerBuilder::LayerManagerDataProperty(), array);
- }
- array->AppendElement(this);
+ SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
+ array.AppendElement(this);
}
void
DisplayItemData::RemoveFrame(nsIFrame* aFrame)
{
MOZ_RELEASE_ASSERT(mLayer);
bool result = mFrameList.RemoveElement(aFrame);
MOZ_RELEASE_ASSERT(result, "Can't remove a frame that wasn't added!");
- nsTArray<DisplayItemData*>* array =
- aFrame->Properties().Get(FrameLayerBuilder::LayerManagerDataProperty());
- MOZ_RELEASE_ASSERT(array, "Must be already stored on the frame!");
- array->RemoveElement(this);
+ SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
+ array.RemoveElement(this);
}
void
DisplayItemData::EndUpdate()
{
MOZ_RELEASE_ASSERT(mLayer);
MOZ_ASSERT(!mItem);
mIsInvalid = false;
@@ -263,19 +256,18 @@ DisplayItemData::~DisplayItemData()
{
MOZ_COUNT_DTOR(DisplayItemData);
MOZ_RELEASE_ASSERT(mLayer);
for (uint32_t i = 0; i < mFrameList.Length(); i++) {
nsIFrame* frame = mFrameList[i];
if (frame == sDestroyedFrame) {
continue;
}
- nsTArray<DisplayItemData*> *array =
- reinterpret_cast<nsTArray<DisplayItemData*>*>(frame->Properties().Get(FrameLayerBuilder::LayerManagerDataProperty()));
- array->RemoveElement(this);
+ SmallPointerArray<DisplayItemData>& array = frame->DisplayItemData();
+ array.RemoveElement(this);
}
MOZ_RELEASE_ASSERT(sAliveDisplayItemDatas && sAliveDisplayItemDatas->Contains(this));
sAliveDisplayItemDatas->RemoveEntry(this);
if (sAliveDisplayItemDatas->Count() == 0) {
delete sAliveDisplayItemDatas;
sAliveDisplayItemDatas = nullptr;
}
@@ -386,18 +378,18 @@ public:
#endif
nsTHashtable<nsRefPtrHashKey<DisplayItemData> > mDisplayItems;
bool mInvalidateAllLayers;
};
/* static */ void
FrameLayerBuilder::DestroyDisplayItemDataFor(nsIFrame* aFrame)
{
- FrameProperties props = aFrame->Properties();
- props.Delete(LayerManagerDataProperty());
+ RemoveFrameFromLayerManager(aFrame, aFrame->DisplayItemData());
+ aFrame->DisplayItemData().Clear();
}
struct AssignedDisplayItem
{
AssignedDisplayItem(nsDisplayItem* aItem,
const DisplayItemClip& aClip,
LayerState aLayerState)
: mItem(aItem)
@@ -1811,25 +1803,22 @@ AssertDisplayItemData(DisplayItemData* a
MOZ_RELEASE_ASSERT(sAliveDisplayItemDatas && sAliveDisplayItemDatas->Contains(aData));
//MOZ_RELEASE_ASSERT(aData->mLayer);
return aData;
}
DisplayItemData*
FrameLayerBuilder::GetDisplayItemData(nsIFrame* aFrame, uint32_t aKey)
{
- const nsTArray<DisplayItemData*>* array =
- aFrame->Properties().Get(LayerManagerDataProperty());
- if (array) {
- for (uint32_t i = 0; i < array->Length(); i++) {
- DisplayItemData* item = AssertDisplayItemData(array->ElementAt(i));
- if (item->mDisplayItemKey == aKey &&
- item->mLayer->Manager() == mRetainingManager) {
- return item;
- }
+ const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
+ for (uint32_t i = 0; i < array.Length(); i++) {
+ DisplayItemData* item = AssertDisplayItemData(array.ElementAt(i));
+ if (item->mDisplayItemKey == aKey &&
+ item->mLayer->Manager() == mRetainingManager) {
+ return item;
}
}
return nullptr;
}
nsACString&
AppendToString(nsACString& s, const nsIntRect& r,
const char* pfx="", const char* sfx="")
@@ -1919,40 +1908,40 @@ GetTranslationForPaintedLayer(PaintedLay
* items with the same frame, then we attempt to retrieve properties
* from the deleted frame.
*
* Cache the destroyed frame pointer here so we can avoid crashing in this case.
*/
/* static */ void
FrameLayerBuilder::RemoveFrameFromLayerManager(const nsIFrame* aFrame,
- nsTArray<DisplayItemData*>* aArray)
+ SmallPointerArray<DisplayItemData>& aArray)
{
MOZ_RELEASE_ASSERT(!sDestroyedFrame);
sDestroyedFrame = aFrame;
// Hold a reference to all the items so that they don't get
// deleted from under us.
nsTArray<RefPtr<DisplayItemData> > arrayCopy;
- for (DisplayItemData* data : *aArray) {
+ for (DisplayItemData* data : aArray) {
arrayCopy.AppendElement(data);
}
#ifdef DEBUG_DISPLAY_ITEM_DATA
if (aArray->Length()) {
LayerManagerData *rootData = aArray->ElementAt(0)->mParent;
while (rootData->mParent) {
rootData = rootData->mParent;
}
printf_stderr("Removing frame %p - dumping display data\n", aFrame);
rootData->Dump();
}
#endif
- for (DisplayItemData* data : *aArray) {
+ for (DisplayItemData* data : aArray) {
PaintedLayer* t = data->mLayer->AsPaintedLayer();
if (t) {
PaintedDisplayItemLayerUserData* paintedData =
static_cast<PaintedDisplayItemLayerUserData*>(t->GetUserData(&gPaintedDisplayItemLayerUserData));
if (paintedData && data->mGeometry) {
nsRegion old = data->mGeometry->ComputeInvalidationRegion();
nsIntRegion rgn = old.ScaleToOutsidePixels(paintedData->mXScale, paintedData->mYScale, paintedData->mAppUnitsPerDevPixel);
rgn.MoveBy(-GetTranslationForPaintedLayer(t));
@@ -1960,17 +1949,16 @@ FrameLayerBuilder::RemoveFrameFromLayerM
paintedData->mRegionToInvalidate.SimplifyOutward(8);
}
}
data->mParent->mDisplayItems.RemoveEntry(data);
}
arrayCopy.Clear();
- delete aArray;
sDestroyedFrame = nullptr;
}
void
FrameLayerBuilder::DidBeginRetainedLayerTransaction(LayerManager* aManager)
{
mRetainingManager = aManager;
LayerManagerData* data = static_cast<LayerManagerData*>
@@ -2041,56 +2029,48 @@ FrameLayerBuilder::WillEndTransaction()
data->mInvalidateAllLayers = false;
}
/* static */ DisplayItemData*
FrameLayerBuilder::GetDisplayItemDataForManager(nsDisplayItem* aItem,
LayerManager* aManager)
{
- const nsTArray<DisplayItemData*>* array =
- aItem->Frame()->Properties().Get(LayerManagerDataProperty());
- if (array) {
- for (uint32_t i = 0; i < array->Length(); i++) {
- DisplayItemData* item = AssertDisplayItemData(array->ElementAt(i));
- if (item->mDisplayItemKey == aItem->GetPerFrameKey() &&
- item->mLayer->Manager() == aManager) {
- return item;
- }
+ const SmallPointerArray<DisplayItemData>& array =
+ aItem->Frame()->DisplayItemData();
+ for (uint32_t i = 0; i < array.Length(); i++) {
+ DisplayItemData* item = AssertDisplayItemData(array.ElementAt(i));
+ if (item->mDisplayItemKey == aItem->GetPerFrameKey() &&
+ item->mLayer->Manager() == aManager) {
+ return item;
}
}
return nullptr;
}
bool
FrameLayerBuilder::HasRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey)
{
- const nsTArray<DisplayItemData*>* array =
- aFrame->Properties().Get(LayerManagerDataProperty());
- if (array) {
- for (uint32_t i = 0; i < array->Length(); i++) {
- if (AssertDisplayItemData(array->ElementAt(i))->mDisplayItemKey == aDisplayItemKey) {
- return true;
- }
+ const SmallPointerArray<DisplayItemData>& array =
+ aFrame->DisplayItemData();
+ for (uint32_t i = 0; i < array.Length(); i++) {
+ if (AssertDisplayItemData(array.ElementAt(i))->mDisplayItemKey == aDisplayItemKey) {
+ return true;
}
}
return false;
}
void
FrameLayerBuilder::IterateRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallback aCallback)
{
- const nsTArray<DisplayItemData*>* array =
- aFrame->Properties().Get(LayerManagerDataProperty());
- if (!array) {
- return;
- }
-
- for (uint32_t i = 0; i < array->Length(); i++) {
- DisplayItemData* data = AssertDisplayItemData(array->ElementAt(i));
+ const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
+
+ for (uint32_t i = 0; i < array.Length(); i++) {
+ DisplayItemData* data = AssertDisplayItemData(array.ElementAt(i));
if (data->mDisplayItemKey != nsDisplayItem::TYPE_ZERO) {
aCallback(aFrame, data);
}
}
}
DisplayItemData*
FrameLayerBuilder::GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey)
@@ -2140,45 +2120,35 @@ FrameLayerBuilder::ClearCachedGeometry(n
if (oldData) {
oldData->mGeometry = nullptr;
}
}
/* static */ Layer*
FrameLayerBuilder::GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey)
{
- const nsTArray<DisplayItemData*>* array =
- aFrame->Properties().Get(LayerManagerDataProperty());
-
- if (!array) {
- return nullptr;
- }
-
- for (uint32_t i = 0; i < array->Length(); i++) {
- DisplayItemData *data = AssertDisplayItemData(array->ElementAt(i));
+ const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
+
+ for (uint32_t i = 0; i < array.Length(); i++) {
+ DisplayItemData *data = AssertDisplayItemData(array.ElementAt(i));
if (data->mDisplayItemKey == aDisplayItemKey) {
return data->mLayer;
}
}
return nullptr;
}
/* static */ PaintedLayer*
FrameLayerBuilder::GetDebugSingleOldPaintedLayerForFrame(nsIFrame* aFrame)
{
- const nsTArray<DisplayItemData*>* array =
- aFrame->Properties().Get(LayerManagerDataProperty());
-
- if (!array) {
- return nullptr;
- }
+ SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
Layer* layer = nullptr;
- for (DisplayItemData* data : *array) {
+ for (DisplayItemData* data : array) {
AssertDisplayItemData(data);
if (!data->mLayer->AsPaintedLayer()) {
continue;
}
if (layer && layer != data->mLayer) {
// More than one layer assigned, bail.
return nullptr;
}
@@ -5803,55 +5773,52 @@ FrameLayerBuilder::InvalidateAllLayers(L
if (data) {
data->mInvalidateAllLayers = true;
}
}
/* static */ void
FrameLayerBuilder::InvalidateAllLayersForFrame(nsIFrame *aFrame)
{
- const nsTArray<DisplayItemData*>* array =
- aFrame->Properties().Get(LayerManagerDataProperty());
- if (array) {
- for (uint32_t i = 0; i < array->Length(); i++) {
- AssertDisplayItemData(array->ElementAt(i))->mParent->mInvalidateAllLayers = true;
- }
+ const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
+
+ for (uint32_t i = 0; i < array.Length(); i++) {
+ AssertDisplayItemData(array.ElementAt(i))->mParent->mInvalidateAllLayers = true;
}
}
/* static */
Layer*
FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, uint32_t aDisplayItemKey)
{
//TODO: This isn't completely correct, since a frame could exist as a layer
// in the normal widget manager, and as a different layer (or no layer)
// in the secondary manager
- const nsTArray<DisplayItemData*>* array =
- aFrame->Properties().Get(LayerManagerDataProperty());
- if (array) {
- for (uint32_t i = 0; i < array->Length(); i++) {
- DisplayItemData *element = AssertDisplayItemData(array->ElementAt(i));
- if (!element->mParent->mLayerManager->IsWidgetLayerManager()) {
- continue;
+ const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();;
+
+ for (uint32_t i = 0; i < array.Length(); i++) {
+ DisplayItemData *element = AssertDisplayItemData(array.ElementAt(i));
+ if (!element->mParent->mLayerManager->IsWidgetLayerManager()) {
+ continue;
+ }
+ if (element->mDisplayItemKey == aDisplayItemKey) {
+ if (element->mOptLayer) {
+ return element->mOptLayer;
}
- if (element->mDisplayItemKey == aDisplayItemKey) {
- if (element->mOptLayer) {
- return element->mOptLayer;
- }
-
- Layer* layer = element->mLayer;
- if (!layer->HasUserData(&gColorLayerUserData) &&
- !layer->HasUserData(&gImageLayerUserData) &&
- !layer->HasUserData(&gPaintedDisplayItemLayerUserData)) {
- return layer;
- }
+
+ Layer* layer = element->mLayer;
+ if (!layer->HasUserData(&gColorLayerUserData) &&
+ !layer->HasUserData(&gImageLayerUserData) &&
+ !layer->HasUserData(&gPaintedDisplayItemLayerUserData)) {
+ return layer;
}
}
}
+
return nullptr;
}
static gfxSize
PredictScaleForContent(nsIFrame* aFrame, nsIFrame* aAncestorWithScale,
const gfxSize& aScale)
{
Matrix4x4 transform = Matrix4x4::Scaling(aScale.width, aScale.height, 1.0);
@@ -5876,24 +5843,20 @@ FrameLayerBuilder::GetPaintedLayerScaleF
if (nsLayoutUtils::IsPopup(f)) {
// Don't examine ancestors of a popup. It won't make sense to check
// the transform from some content inside the popup to some content
// which is an ancestor of the popup.
break;
}
- const nsTArray<DisplayItemData*>* array =
- f->Properties().Get(LayerManagerDataProperty());
- if (!array) {
- continue;
- }
-
- for (uint32_t i = 0; i < array->Length(); i++) {
- Layer* layer = AssertDisplayItemData(array->ElementAt(i))->mLayer;
+ const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
+
+ for (uint32_t i = 0; i < array.Length(); i++) {
+ Layer* layer = AssertDisplayItemData(array.ElementAt(i))->mLayer;
ContainerLayer* container = layer->AsContainerLayer();
if (!container ||
!layer->Manager()->IsWidgetLayerManager()) {
continue;
}
for (Layer* l = container->GetFirstChild(); l; l = l->GetNextSibling()) {
PaintedDisplayItemLayerUserData* data =
static_cast<PaintedDisplayItemLayerUserData*>
@@ -6310,30 +6273,25 @@ FrameLayerBuilder::CheckDOMModified()
FrameLayerBuilder::DumpRetainedLayerTree(LayerManager* aManager, std::stringstream& aStream, bool aDumpHtml)
{
aManager->Dump(aStream, "", aDumpHtml);
}
nsDisplayItemGeometry*
FrameLayerBuilder::GetMostRecentGeometry(nsDisplayItem* aItem)
{
- typedef nsTArray<DisplayItemData*> DataArray;
+ typedef SmallPointerArray<DisplayItemData> DataArray;
// Retrieve the array of DisplayItemData associated with our frame.
- FrameProperties properties = aItem->Frame()->Properties();
- const DataArray* dataArray =
- properties.Get(LayerManagerDataProperty());
- if (!dataArray) {
- return nullptr;
- }
+ const DataArray& dataArray = aItem->Frame()->DisplayItemData();
// Find our display item data, if it exists, and return its geometry.
uint32_t itemPerFrameKey = aItem->GetPerFrameKey();
- for (uint32_t i = 0; i < dataArray->Length(); i++) {
- DisplayItemData* data = AssertDisplayItemData(dataArray->ElementAt(i));
+ for (uint32_t i = 0; i < dataArray.Length(); i++) {
+ DisplayItemData* data = AssertDisplayItemData(dataArray.ElementAt(i));
if (data->GetDisplayItemKey() == itemPerFrameKey) {
return data->GetGeometry();
}
}
return nullptr;
}
--- a/layout/painting/FrameLayerBuilder.h
+++ b/layout/painting/FrameLayerBuilder.h
@@ -563,26 +563,23 @@ public:
/**
* Stores a Layer as the dedicated layer in the DisplayItemData for a given frame/key pair.
*
* Used when we optimize a PaintedLayer into an ImageLayer and want to retroactively update the
* DisplayItemData so we can retrieve the layer from within layout.
*/
void StoreOptimizedLayerForFrame(nsDisplayItem* aItem, Layer* aLayer);
- NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(LayerManagerDataProperty,
- nsTArray<DisplayItemData*>,
- RemoveFrameFromLayerManager)
+ static void RemoveFrameFromLayerManager(const nsIFrame* aFrame,
+ SmallPointerArray<DisplayItemData>& aArray);
+
protected:
friend class LayerManagerData;
- static void RemoveFrameFromLayerManager(const nsIFrame* aFrame,
- nsTArray<DisplayItemData*>* aArray);
-
/**
* Given a frame and a display item key that uniquely identifies a
* display item for the frame, find the layer that was last used to
* render that display item. Returns null if there is no such layer.
* This could be a dedicated layer for the display item, or a PaintedLayer
* that renders many display items.
*/
DisplayItemData* GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey);