From 57198c4af7d5a39d19a5991412f08f0d3642b77e Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Wed, 29 Aug 2012 17:48:41 +1200 Subject: [PATCH] Bug 539356 - Part 14 - Handle multiple widget layer managers retaining data for the same frame. r=roc --- layout/base/FrameLayerBuilder.cpp | 153 +++++++++++++++++++++--------- layout/base/FrameLayerBuilder.h | 66 +++++++++++-- layout/base/nsDisplayList.cpp | 3 + 3 files changed, 170 insertions(+), 52 deletions(-) diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 26cf2b95c0fb..741f7a11cf3a 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -93,11 +93,11 @@ public: mFramesWithLayers.Init(); } ~LayerManagerData() { + MOZ_COUNT_DTOR(LayerManagerData); // Remove display item data properties now, since we won't be able // to find these frames again without mFramesWithLayers. mFramesWithLayers.EnumerateEntries( FrameLayerBuilder::RemoveDisplayItemDataForFrame, this); - MOZ_COUNT_DTOR(LayerManagerData); } /** @@ -107,6 +107,14 @@ public: bool mInvalidateAllLayers; }; +/* static */ void +FrameLayerBuilder::DestroyDisplayItemDataFor(nsIFrame* aFrame) +{ + FrameProperties props = aFrame->Properties(); + props.Delete(LayerManagerDataProperty()); + props.Delete(LayerManagerSecondaryDataProperty()); +} + namespace { // a global cache of image containers used for mask layers @@ -627,6 +635,61 @@ ThebesDisplayItemLayerUserData* GetThebesDisplayItemLayerUserData(Layer* aLayer) } // anonymous namespace +uint8_t gLayerManagerSecondary; + +bool FrameLayerBuilder::sWidgetManagerSecondary = nullptr; + +/* static */ const FramePropertyDescriptor* +FrameLayerBuilder::GetDescriptorForManager(LayerManager* aManager) +{ + bool secondary = sWidgetManagerSecondary; + if (aManager) { + secondary = !!static_cast(aManager->GetUserData(&gLayerManagerSecondary)); + } + + return secondary ? LayerManagerSecondaryDataProperty() : LayerManagerDataProperty(); +} + +LayerManagerData* +FrameLayerBuilder::GetManagerData(nsIFrame* aFrame, LayerManager* aManager) +{ + FrameProperties props = aFrame->Properties(); + return static_cast(props.Get(GetDescriptorForManager(aManager))); +} + +void +FrameLayerBuilder::SetManagerData(nsIFrame* aFrame, LayerManagerData* aData) +{ + FrameProperties props = aFrame->Properties(); + const FramePropertyDescriptor* desc = GetDescriptorForManager(nullptr); + + props.Remove(desc); + if (aData) { + props.Set(desc, aData); + } +} + +void +FrameLayerBuilder::ClearManagerData(nsIFrame* aFrame) +{ + SetManagerData(aFrame, nullptr); +} + +void +FrameLayerBuilder::ClearManagerData(nsIFrame* aFrame, LayerManagerData* aData) +{ + NS_ABORT_IF_FALSE(aData, "Must have a widget manager to check for manager data!"); + + FrameProperties props = aFrame->Properties(); + if (aData == static_cast(props.Get(LayerManagerDataProperty()))) { + props.Remove(LayerManagerDataProperty()); + return; + } + if (aData == static_cast(props.Get(LayerManagerSecondaryDataProperty()))) { + props.Remove(LayerManagerSecondaryDataProperty()); + return; + } +} /* static */ void FrameLayerBuilder::Shutdown() { @@ -805,6 +868,9 @@ FrameLayerBuilder::DidBeginRetainedLayerTransaction(LayerManager* aManager) (aManager->GetUserData(&gLayerManagerUserData)); if (data) { mInvalidateAllLayers = data->mInvalidateAllLayers; + } else { + data = new LayerManagerData(); + aManager->SetUserData(&gLayerManagerUserData, data); } } @@ -824,13 +890,10 @@ FrameLayerBuilder::WillEndTransaction() // We need to save the data we'll need to support retaining. LayerManagerData* data = static_cast (mRetainingManager->GetUserData(&gLayerManagerUserData)); - if (data) { - // Update all the frames that used to have layers. - data->mFramesWithLayers.EnumerateEntries(UpdateDisplayItemDataForFrame, this); - } else { - data = new LayerManagerData(); - mRetainingManager->SetUserData(&gLayerManagerUserData, data); - } + NS_ASSERTION(data, "Must have data!"); + // Update all the frames that used to have layers. + data->mFramesWithLayers.EnumerateEntries(UpdateDisplayItemDataForFrame, this); + // Now go through all the frames that didn't have any retained // display items before, and record those retained display items. // This also empties mNewDisplayItemData. @@ -881,28 +944,24 @@ FrameLayerBuilder::UpdateDisplayItemDataForFrame(DisplayItemDataEntry* aEntry, { FrameLayerBuilder* builder = static_cast(aUserArg); nsIFrame* f = aEntry->GetKey(); - FrameProperties props = f->Properties(); DisplayItemDataEntry* newDisplayItems = builder ? builder->mNewDisplayItemData.GetEntry(f) : nullptr; LayerManagerData* managerData = static_cast (builder->GetRetainingLayerManager()->GetUserData(&gLayerManagerUserData)); - LayerManagerData* data = static_cast(props.Get(LayerManagerDataProperty())); + LayerManagerData* data = GetManagerData(f); if (!newDisplayItems || newDisplayItems->mData.IsEmpty()) { // This frame was visible, but isn't anymore. if (newDisplayItems) { builder->mNewDisplayItemData.RawRemoveEntry(newDisplayItems); } if (data == managerData) { - props.Remove(LayerManagerDataProperty()); + ClearManagerData(f); } return PL_DHASH_REMOVE; } - if (data) { - props.Remove(LayerManagerDataProperty()); - } - props.Set(LayerManagerDataProperty(), managerData); + SetManagerData(f, managerData); // Steal the list of display item layers and invalid region aEntry->mData.SwapElements(newDisplayItems->mData); @@ -920,12 +979,7 @@ FrameLayerBuilder::RemoveDisplayItemDataForFrame(DisplayItemDataEntry* aEntry, // If this was called from a frame destructor then the prop is definitely already gone, // and we could crash trying to check. See the definition of sDestroyedFrame. if (f != sDestroyedFrame) { - FrameProperties props = f->Properties(); - bool found; - LayerManagerData* data = static_cast(props.Get(LayerManagerDataProperty())); - if (data == managerData) { - props.Remove(LayerManagerDataProperty(), &found); - } + ClearManagerData(f, managerData); } return PL_DHASH_REMOVE; } @@ -936,7 +990,6 @@ FrameLayerBuilder::StoreNewDisplayItemData(DisplayItemDataEntry* aEntry, { LayerManagerData* data = static_cast(aUserArg); nsIFrame* f = aEntry->GetKey(); - FrameProperties props = f->Properties(); // Remember that this frame has display items in retained layers NS_ASSERTION(!data->mFramesWithLayers.GetEntry(f), @@ -949,21 +1002,36 @@ FrameLayerBuilder::StoreNewDisplayItemData(DisplayItemDataEntry* aEntry, // When a frame has multiple layer managers (main, inactive, svg), we // only need to store the outermost one since that will be enough to // invalidate the entire region covered by all the children. - props.Remove(LayerManagerDataProperty()); - props.Set(LayerManagerDataProperty(), data); + SetManagerData(f, data); return PL_DHASH_REMOVE; } +/** + * Attempts to find the LayerManagerData for the widget manager + * for the given frame, nullptr otherwise. + */ +static LayerManagerData* +GetDefaultLayerManagerDataForFrame(nsIFrame* aFrame) +{ + FrameProperties props = aFrame->Properties(); + return static_cast(props.Get(FrameLayerBuilder::LayerManagerDataProperty())); +} + /* static */ FrameLayerBuilder::DisplayItemData* FrameLayerBuilder::GetDisplayItemDataForManager(nsIFrame* aFrame, uint32_t aDisplayItemKey, LayerManager* aManager) { - LayerManagerData* managerData = static_cast - (aManager->GetUserData(&gLayerManagerUserData)); - if (!managerData) { + LayerManagerData *data; + if (!aManager) { + data = GetDefaultLayerManagerDataForFrame(aFrame); + } else { + data = static_cast(aManager->GetUserData(&gLayerManagerUserData)); + } + + if (!data) { return nullptr; } - DisplayItemDataEntry *entry = managerData->mFramesWithLayers.GetEntry(aFrame); + DisplayItemDataEntry *entry = data->mFramesWithLayers.GetEntry(aFrame); if (!entry) { return nullptr; } @@ -1073,8 +1141,7 @@ FrameLayerBuilder::GetOldLayerFor(nsDisplayItem* aItem, nsDisplayItemGeometry** /* static */ Layer* FrameLayerBuilder::GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey) { - FrameProperties props = aFrame->Properties(); - LayerManagerData* data = static_cast(props.Get(LayerManagerDataProperty())); + LayerManagerData* data = GetManagerData(aFrame); if (!data) { return nullptr; } @@ -2832,24 +2899,20 @@ FrameLayerBuilder::InvalidateAllLayers(LayerManager* aManager) Layer* FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, uint32_t aDisplayItemKey) { - FrameProperties props = aFrame->Properties(); - LayerManagerData* data = static_cast(props.Get(LayerManagerDataProperty())); + //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 + + DisplayItemData *data = GetDisplayItemDataForManager(aFrame, aDisplayItemKey, nullptr); if (!data) { return nullptr; } - DisplayItemDataEntry *entry = data->mFramesWithLayers.GetEntry(aFrame); - if (!entry) { - return nullptr; - } - for (uint32_t i = 0; i < entry->mData.Length(); ++i) { - if (entry->mData.ElementAt(i).mDisplayItemKey == aDisplayItemKey) { - Layer* layer = entry->mData.ElementAt(i).mLayer; - if (!layer->HasUserData(&gColorLayerUserData) && - !layer->HasUserData(&gImageLayerUserData) && - !layer->HasUserData(&gThebesDisplayItemLayerUserData)) - return layer; - } + Layer* layer = data->mLayer; + if (!layer->HasUserData(&gColorLayerUserData) && + !layer->HasUserData(&gImageLayerUserData) && + !layer->HasUserData(&gThebesDisplayItemLayerUserData)) { + return layer; } return nullptr; } @@ -2882,7 +2945,7 @@ FrameLayerBuilder::GetThebesLayerScaleForFrame(nsIFrame* aFrame) // Some frames with NS_FRAME_HAS_CONTAINER_LAYER may not have display items. // In particular the root frame probably doesn't! if (!entry) - continue; + continue; nsTArray >* array = &entry->mData; for (uint32_t i = 0; i < array->Length(); ++i) { Layer* layer = array->ElementAt(i)->mLayer; diff --git a/layout/base/FrameLayerBuilder.h b/layout/base/FrameLayerBuilder.h index 75c7013526d7..aed6b00d2f27 100644 --- a/layout/base/FrameLayerBuilder.h +++ b/layout/base/FrameLayerBuilder.h @@ -43,6 +43,11 @@ enum LayerState { LAYER_SVG_EFFECTS }; +extern uint8_t gLayerManagerSecondary; + +class LayerManagerSecondary : public layers::LayerUserData { +}; + class RefCountedRegion : public RefCounted { public: RefCountedRegion() : mIsInfinite(false) {} @@ -281,6 +286,47 @@ public: LayerState aLayerState, const nsPoint& aTopLeft); + /** + * Set the current top-level LayerManager for the widget being + * painted. + */ + static void SetWidgetLayerManager(LayerManager* aManager) + { + LayerManagerSecondary* secondary = + static_cast(aManager->GetUserData(&gLayerManagerSecondary)); + sWidgetManagerSecondary = !!secondary; + } + + /** + * Gets the frame property descriptor for the given manager, or for the current + * widget layer manager if nullptr is passed. + */ + static const FramePropertyDescriptor* GetDescriptorForManager(LayerManager* aManager); + + /** + * Get the LayerManagerData for a given frame and layer manager. If no layer manager + * is passed, then the current widget layer manager is used. + */ + static LayerManagerData* GetManagerData(nsIFrame* aFrame, LayerManager* aManager = nullptr); + + /** + * Set the LayerManagerData for a given frame and current widget layer manager. + * This replaces any existing data for the same frame/layer manager pair. + */ + static void SetManagerData(nsIFrame* aFrame, LayerManagerData* aData); + + /** + * Clears the current LayerManagerData for the given frame and current widget + * layer manager. + */ + static void ClearManagerData(nsIFrame* aFrame); + + /** + * Clears any references to the given LayerManagerData for the given frame + * and belonging to any layer manager. + */ + static void ClearManagerData(nsIFrame* aFrame, LayerManagerData* aData); + /** * Calls GetOldLayerForFrame on the underlying frame of the display item, * and each subsequent merged frame if no layer is found for the underlying @@ -309,10 +355,7 @@ public: * Destroy any stored LayerManagerDataProperty and the associated data for * aFrame. */ - static void DestroyDisplayItemDataFor(nsIFrame* aFrame) - { - aFrame->Properties().Delete(LayerManagerDataProperty()); - } + static void DestroyDisplayItemDataFor(nsIFrame* aFrame); LayerManager* GetRetainingLayerManager() { return mRetainingManager; } @@ -440,6 +483,12 @@ public: return !(*this == aOther); } }; + + NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(LayerManagerDataProperty, + RemoveFrameFromLayerManager) + + NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(LayerManagerSecondaryDataProperty, + RemoveFrameFromLayerManager) protected: /** @@ -492,9 +541,6 @@ protected: */ DisplayItemData* GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey); - NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(LayerManagerDataProperty, - RemoveFrameFromLayerManager) - /** * We accumulate DisplayItemData elements in a hashtable during * the paint process, and store them in the frame property only when @@ -704,6 +750,12 @@ protected: uint32_t mContainerLayerGeneration; uint32_t mMaxContainerLayerGeneration; + + /** + * True if the current top-level LayerManager for the widget being + * painted is marked as being a 'secondary' LayerManager. + */ + static bool sWidgetManagerSecondary; }; } diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 90bd2d2a77da..88a2ec30464d 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -970,6 +970,7 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder, "Must call ComputeVisibility before calling Paint"); nsRefPtr layerManager; + bool widgetTransaction = false; bool allowRetaining = false; bool doBeginTransaction = true; nsIView *view = nullptr; @@ -983,6 +984,8 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder, layerManager = window->GetLayerManager(&allowRetaining); if (layerManager) { doBeginTransaction = !(aFlags & PAINT_EXISTING_TRANSACTION); + FrameLayerBuilder::SetWidgetLayerManager(layerManager); + widgetTransaction = true; } } }