bug 1368547 part 2 - Remove nsFrameManager/PresShell methods dealing with placeholders and introduce a nsIFrame::GetPlaceholderFrame() convenience method. r=jfkthame
authorMats Palmgren <mats@mozilla.com>
Wed, 31 May 2017 21:29:49 +0200
changeset 409781 45409ba9a985de2d6572055f5d6f552dff74f4f6
parent 409780 ddcdb354143a9018a9bc94cef7a395ef46873f8b
child 409782 bd52d785f0d482d6a106b5d5603c3c334a521b2e
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs1368547
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 1368547 part 2 - Remove nsFrameManager/PresShell methods dealing with placeholders and introduce a nsIFrame::GetPlaceholderFrame() convenience method. r=jfkthame MozReview-Commit-ID: GBUiUBqJxhQ
layout/base/PresShell.cpp
layout/base/PresShell.h
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsFrameManager.cpp
layout/base/nsFrameManager.h
layout/base/nsFrameTraversal.cpp
layout/base/nsIPresShell.h
layout/base/nsLayoutUtils.cpp
layout/generic/ReflowInput.cpp
layout/generic/nsAbsoluteContainingBlock.cpp
layout/generic/nsBlockFrame.cpp
layout/generic/nsFirstLetterFrame.cpp
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/generic/nsIFrameInlines.h
layout/generic/nsTextFrame.cpp
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -4607,22 +4607,16 @@ PresShell::StyleRuleAdded(StyleSheet* aS
 }
 
 void
 PresShell::StyleRuleRemoved(StyleSheet* aStyleSheet)
 {
   RecordStyleSheetChange(aStyleSheet, StyleSheet::ChangeType::RuleRemoved);
 }
 
-nsPlaceholderFrame*
-PresShell::GetPlaceholderFrameFor(nsIFrame* aFrame) const
-{
-  return mFrameConstructor->GetPlaceholderFrameFor(aFrame);
-}
-
 nsresult
 PresShell::RenderDocument(const nsRect& aRect, uint32_t aFlags,
                           nscolor aBackgroundColor,
                           gfxContext* aThebesContext)
 {
   NS_ENSURE_TRUE(!(aFlags & RENDER_IS_UNTRUSTED), NS_ERROR_NOT_IMPLEMENTED);
 
   nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -117,17 +117,16 @@ public:
   virtual void BeginObservingDocument() override;
   virtual void EndObservingDocument() override;
   virtual nsresult Initialize(nscoord aWidth, nscoord aHeight) override;
   virtual nsresult ResizeReflow(nscoord aWidth, nscoord aHeight, nscoord aOldWidth = 0, nscoord aOldHeight = 0) override;
   virtual nsresult ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight, nscoord aOldWidth, nscoord aOldHeight) override;
   virtual nsIPageSequenceFrame* GetPageSequenceFrame() const override;
   virtual nsCanvasFrame* GetCanvasFrame() const override;
 
-  virtual nsPlaceholderFrame* GetPlaceholderFrameFor(nsIFrame* aFrame) const override;
   virtual void FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty,
                                 nsFrameState aBitToAdd,
                                 ReflowRootHandling aRootHandling =
                                   eInferFromBitToAdd) override;
   virtual void FrameNeedsToContinueReflow(nsIFrame *aFrame) override;
   virtual void CancelAllPendingReflows() override;
   virtual bool IsSafeToFlush() const override;
   virtual void DoFlushPendingNotifications(mozilla::FlushType aType) override;
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -715,20 +715,19 @@ nsAbsoluteItems::nsAbsoluteItems(nsConta
   : containingBlock(aContainingBlock)
 {
 }
 
 // Additional behavior is that it sets the frame's NS_FRAME_OUT_OF_FLOW flag
 void
 nsAbsoluteItems::AddChild(nsIFrame* aChild)
 {
-  NS_ASSERTION(aChild->PresContext()->FrameManager()->
-               GetPlaceholderFrameFor(aChild),
+  aChild->AddStateBits(NS_FRAME_OUT_OF_FLOW);
+  NS_ASSERTION(aChild->GetPlaceholderFrame(),
                "Child without placeholder being added to nsAbsoluteItems?");
-  aChild->AddStateBits(NS_FRAME_OUT_OF_FLOW);
   nsFrameItems::AddChild(aChild);
 }
 
 // -----------------------------------------------------------
 
 // Structure for saving the existing state when pushing/poping containing
 // blocks. The destructor restores the state to its previous state
 class MOZ_STACK_CLASS nsFrameConstructorSaveState {
@@ -3082,24 +3081,22 @@ nsCSSFrameConstructor::CreatePlaceholder
 
   // The placeholder frame gets a pseudo style context
   nsPlaceholderFrame* placeholderFrame =
     (nsPlaceholderFrame*)NS_NewPlaceholderFrame(aPresShell, placeholderStyle,
                                                 aTypeBit);
 
   placeholderFrame->Init(aContent, aParentFrame, aPrevInFlow);
 
-  // The placeholder frame has a pointer back to the out-of-flow frame
+  // Associate the placeholder/out-of-flow with each other.
   placeholderFrame->SetOutOfFlowFrame(aFrame);
+  aFrame->SetProperty(nsIFrame::PlaceholderFrameProperty(), placeholderFrame);
 
   aFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
 
-  // Add mapping from absolutely positioned frame to its placeholder frame
-  aPresShell->FrameManager()->RegisterPlaceholderFrame(placeholderFrame);
-
   return placeholderFrame;
 }
 
 // Clears any lazy bits set in the range [aStartContent, aEndContent).  If
 // aEndContent is null, that means to clear bits in all siblings starting with
 // aStartContent.  aStartContent must not be null unless aEndContent is also
 // null.  We do this so that when new children are inserted under elements whose
 // frame is a leaf the new children don't cause us to try to construct frames
@@ -6784,17 +6781,17 @@ nsCSSFrameConstructor::FindFrameForConte
     // XXX the GetContent() != aContent check is needed due to bug 135040.
     // Remove it once that's fixed.
     return nullptr;
   }
 
   // If the frame is out-of-flow, GetPrimaryFrame() will have returned the
   // out-of-flow frame; we want the placeholder.
   if (sibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
-    nsIFrame* placeholderFrame = GetPlaceholderFrameFor(sibling);
+    nsIFrame* placeholderFrame = sibling->GetPlaceholderFrame();
     NS_ASSERTION(placeholderFrame, "no placeholder for out-of-flow frame");
     sibling = placeholderFrame;
   }
 
   // The frame we have now should never be a continuation
   NS_ASSERTION(!sibling->GetPrevContinuation(), "How did that happen?");
 
   if (aPrevSibling) {
@@ -8211,17 +8208,17 @@ nsCSSFrameConstructor::ContentRangeInser
     if (haveFirstLetterStyle) {
       // If our current insertion.mParentFrame is a Letter frame, use its parent as our
       // new parent hint
       if (insertion.mParentFrame->IsLetterFrame()) {
         // If insertion.mParentFrame is out of flow, then we actually want the parent of
         // the placeholder frame.
         if (insertion.mParentFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
           nsPlaceholderFrame* placeholderFrame =
-            GetPlaceholderFrameFor(insertion.mParentFrame);
+            insertion.mParentFrame->GetPlaceholderFrame();
           NS_ASSERTION(placeholderFrame, "No placeholder for out-of-flow?");
           insertion.mParentFrame = placeholderFrame->GetParent();
         } else {
           insertion.mParentFrame = insertion.mParentFrame->GetParent();
         }
       }
 
       // Remove the old letter frames before doing the insertion
@@ -8722,17 +8719,17 @@ nsCSSFrameConstructor::ContentRemoved(ns
       accService->ContentRemoved(mPresShell, aChild);
     }
 #endif
 
     // Examine the containing-block for the removed content and see if
     // :first-letter style applies.
     nsIFrame* inflowChild = childFrame;
     if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
-      inflowChild = GetPlaceholderFrameFor(childFrame);
+      inflowChild = childFrame->GetPlaceholderFrame();
       NS_ASSERTION(inflowChild, "No placeholder for out-of-flow?");
     }
     nsContainerFrame* containingBlock =
       GetFloatContainingBlock(inflowChild->GetParent());
     bool haveFLS = containingBlock && HasFirstLetterStyle(containingBlock);
     if (haveFLS) {
       // Trap out to special routine that handles adjusting a blocks
       // frame tree when first-letter style is present.
@@ -8778,17 +8775,17 @@ nsCSSFrameConstructor::ContentRemoved(ns
       putchar('\n');
       parentFrame->List(stdout, 0);
     }
 #endif
 
 
     // Notify the parent frame that it should delete the frame
     if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
-      childFrame = GetPlaceholderFrameFor(childFrame);
+      childFrame = childFrame->GetPlaceholderFrame();
       NS_ASSERTION(childFrame, "Missing placeholder frame for out of flow.");
       parentFrame = childFrame->GetParent();
     }
     RemoveFrame(nsLayoutUtils::GetChildListNameFor(childFrame), childFrame);
 
     if (isRoot) {
       mRootElementFrame = nullptr;
       mRootElementStyleFrame = nullptr;
@@ -9420,17 +9417,17 @@ nsCSSFrameConstructor::ReplicateFixedFra
   // places in frame construction can't assume a filter is
   // initialized!
 
   // Iterate across fixed frames and replicate each whose placeholder is a
   // descendant of aFrame. (We don't want to explicitly copy placeholders that
   // are within fixed frames, because that would cause duplicates on the new
   // page - bug 389619)
   for (nsIFrame* fixed = firstFixed; fixed; fixed = fixed->GetNextSibling()) {
-    nsIFrame* prevPlaceholder = GetPlaceholderFrameFor(fixed);
+    nsIFrame* prevPlaceholder = fixed->GetPlaceholderFrame();
     if (prevPlaceholder &&
         nsLayoutUtils::IsProperAncestorFrame(prevCanvasFrame, prevPlaceholder)) {
       // We want to use the same style as the primary style frame for
       // our content
       nsIContent* content = fixed->GetContent();
       nsStyleContext* styleContext =
         nsLayoutUtils::GetStyleFrame(content)->StyleContext();
       FrameConstructionItemList items;
@@ -9686,17 +9683,17 @@ nsCSSFrameConstructor::MaybeRecreateCont
                                aDestroyedFramesFor);
       return true;
     }
   }
 
   // Now check for possibly needing to reconstruct due to a pseudo parent
   nsIFrame* inFlowFrame =
     (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) ?
-      GetPlaceholderFrameFor(aFrame) : aFrame;
+      aFrame->GetPlaceholderFrame() : aFrame;
   MOZ_ASSERT(inFlowFrame, "How did that happen?");
   MOZ_ASSERT(inFlowFrame == inFlowFrame->FirstContinuation(),
              "placeholder for primary frame has previous continuations?");
   nsIFrame* parent = inFlowFrame->GetParent();
   // For the case of ruby pseudo parent, effectively, only pseudo rb/rt frame
   // need to be checked here, since all other types of parent will be catched
   // by "Check ruby containers" section below.
   if (IsTableOrRubyPseudo(parent)) {
@@ -11885,17 +11882,17 @@ nsCSSFrameConstructor::RemoveFloatingFir
   // Take the text frame away from the letter frame (so it isn't
   // destroyed when we destroy the letter frame).
   nsIFrame* textFrame = floatFrame->PrincipalChildList().FirstChild();
   if (!textFrame) {
     return;
   }
 
   // Discover the placeholder frame for the letter frame
-  nsPlaceholderFrame* placeholderFrame = GetPlaceholderFrameFor(floatFrame);
+  nsPlaceholderFrame* placeholderFrame = floatFrame->GetPlaceholderFrame();
   if (!placeholderFrame) {
     // Somethings really wrong
     return;
   }
   nsContainerFrame* parentFrame = placeholderFrame->GetParent();
   if (!parentFrame) {
     // Somethings really wrong
     return;
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -112,66 +112,31 @@ nsFrameManager::~nsFrameManager()
 void
 nsFrameManager::Destroy()
 {
   NS_ASSERTION(mPresShell, "Frame manager already shut down.");
 
   // Destroy the frame hierarchy.
   mPresShell->SetIgnoreFrameDestruction(true);
 
-  // Unregister all placeholders before tearing down the frame tree
-  nsFrameManager::ClearPlaceholderFrameMap();
-
   if (mRootFrame) {
     mRootFrame->Destroy();
     mRootFrame = nullptr;
   }
 
   delete mUndisplayedMap;
   mUndisplayedMap = nullptr;
   delete mDisplayContentsMap;
   mDisplayContentsMap = nullptr;
 
   mPresShell = nullptr;
 }
 
 //----------------------------------------------------------------------
 
-// Placeholder frame functions
-nsPlaceholderFrame*
-nsFrameManager::GetPlaceholderFrameFor(const nsIFrame* aFrame)
-{
-  MOZ_ASSERT(aFrame);
-  MOZ_ASSERT(aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW));
-  return aFrame->GetProperty(nsIFrame::PlaceholderFrameProperty());
-}
-
-void
-nsFrameManager::RegisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame)
-{
-  MOZ_ASSERT(aPlaceholderFrame);
-  MOZ_ASSERT(!GetPlaceholderFrameFor(aPlaceholderFrame->GetOutOfFlowFrame()),
-             "Registering a placeholder for a frame that already has a placeholder!");
-  aPlaceholderFrame->GetOutOfFlowFrame()->SetProperty(nsIFrame::PlaceholderFrameProperty(), aPlaceholderFrame);
-}
-
-void
-nsFrameManager::UnregisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame)
-{
-  MOZ_ASSERT(aPlaceholderFrame);
-  aPlaceholderFrame->GetOutOfFlowFrame()->DeleteProperty(nsIFrame::PlaceholderFrameProperty());
-}
-
-void
-nsFrameManager::ClearPlaceholderFrameMap()
-{
-}
-
-//----------------------------------------------------------------------
-
 static nsIContent*
 ParentForUndisplayedMap(const nsIContent* aContent)
 {
   MOZ_ASSERT(aContent);
 
   nsIContent* parent = aContent->GetParentElementCrossingShadowRoot();
   MOZ_ASSERT(parent || !aContent->GetParent(), "no non-elements");
 
@@ -469,17 +434,17 @@ nsFrameManager::RemoveFrame(ChildListID 
   // is important in the presence of absolute positioning
   aOldFrame->InvalidateFrameForRemoval();
 
   NS_ASSERTION(!aOldFrame->GetPrevContinuation() ||
                // exception for nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames
                aOldFrame->IsTextFrame(),
                "Must remove first continuation.");
   NS_ASSERTION(!(aOldFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW &&
-                 GetPlaceholderFrameFor(aOldFrame)),
+                 aOldFrame->GetPlaceholderFrame()),
                "Must call RemoveFrame on placeholder for out-of-flows.");
   nsContainerFrame* parentFrame = aOldFrame->GetParent();
   if (parentFrame->IsAbsoluteContainer() &&
       aListID == parentFrame->GetAbsoluteListID()) {
     parentFrame->GetAbsoluteContainingBlock()->
       RemoveFrame(parentFrame, aListID, aOldFrame);
   } else {
     parentFrame->RemoveFrame(aListID, aOldFrame);
--- a/layout/base/nsFrameManager.h
+++ b/layout/base/nsFrameManager.h
@@ -46,19 +46,17 @@ struct UndisplayedNode : public LinkedLi
 
   nsCOMPtr<nsIContent> mContent;
   RefPtr<nsStyleContext> mStyle;
 };
 
 } // namespace mozilla
 
 /**
- * Frame manager interface. The frame manager serves two purposes:
- * <li>provides a service for mapping from content to frame and from
- * out-of-flow frame to placeholder frame.
+ * Frame manager interface. The frame manager serves one purpose:
  * <li>handles structural modifications to the frame model. If the frame model
  * lock can be acquired, then the changes are processed immediately; otherwise,
  * they're queued and processed later.
  *
  * Do not add virtual methods (a vtable pointer) or members to this class, or
  * else you'll break the validity of the reinterpret_cast in nsIPresShell's
  * FrameManager() method.
  */
@@ -75,23 +73,16 @@ public:
 
   /*
    * After Destroy is called, it is an error to call any FrameManager methods.
    * Destroy should be called when the frame tree managed by the frame
    * manager is no longer being displayed.
    */
   void Destroy();
 
-  // Placeholder frame functions
-  nsPlaceholderFrame* GetPlaceholderFrameFor(const nsIFrame* aFrame);
-  void RegisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame);
-  void UnregisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame);
-
-  void ClearPlaceholderFrameMap();
-
   // Mapping undisplayed content
   nsStyleContext* GetUndisplayedContent(const nsIContent* aContent)
   {
     if (!mUndisplayedMap) {
       return nullptr;
     }
     return GetStyleContextInMap(mUndisplayedMap, aContent);
   }
--- a/layout/base/nsFrameTraversal.cpp
+++ b/layout/base/nsFrameTraversal.cpp
@@ -486,18 +486,17 @@ nsFrameIterator::GetPrevSiblingInner(nsI
 
 
 nsIFrame*
 nsFrameIterator::GetPlaceholderFrame(nsIFrame* aFrame)
 {
   if (MOZ_LIKELY(!aFrame || !aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW))) {
     return aFrame;
   }
-  nsIFrame* placeholder =
-    aFrame->PresContext()->PresShell()->GetPlaceholderFrameFor(aFrame);
+  nsIFrame* placeholder = aFrame->GetPlaceholderFrame();
   return placeholder ? placeholder : aFrame;
 }
 
 bool
 nsFrameIterator::IsPopupFrame(nsIFrame* aFrame)
 {
   // If skipping popup checks, pretend this isn't one.
   if (mSkipPopupChecks) {
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -72,17 +72,16 @@ class nsILayoutHistoryState;
 class nsIReflowCallback;
 class nsIDOMNode;
 class nsCSSFrameConstructor;
 class nsISelection;
 template<class E> class nsCOMArray;
 class AutoWeakFrame;
 class WeakFrame;
 class nsIScrollableFrame;
-class nsPlaceholderFrame;
 class gfxContext;
 class nsIDOMEvent;
 class nsDisplayList;
 class nsDisplayListBuilder;
 class nsPIDOMWindowOuter;
 struct nsPoint;
 class nsINode;
 struct nsRect;
@@ -448,22 +447,16 @@ public:
 
   /**
   * Returns the canvas frame associated with the frame hierarchy.
   * Returns nullptr if is XUL document.
   */
   virtual nsCanvasFrame* GetCanvasFrame() const = 0;
 
   /**
-   * Gets the placeholder frame associated with the specified frame. This is
-   * a helper frame that forwards the request to the frame manager.
-   */
-  virtual nsPlaceholderFrame* GetPlaceholderFrameFor(nsIFrame* aFrame) const = 0;
-
-  /**
    * Tell the pres shell that a frame needs to be marked dirty and needs
    * Reflow.  It's OK if this is an ancestor of the frame needing reflow as
    * long as the ancestor chain between them doesn't cross a reflow root.
    *
    * The bit to add should be NS_FRAME_IS_DIRTY, NS_FRAME_HAS_DIRTY_CHILDREN
    * or nsFrameState(0); passing 0 means that dirty bits won't be set on the
    * frame or its ancestors/descendants, but that intrinsic widths will still
    * be marked dirty.  Passing aIntrinsicDirty = eResize and aBitToAdd = 0
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -4490,18 +4490,17 @@ nsLayoutUtils::GetNonGeneratedAncestor(n
   return f;
 }
 
 nsIFrame*
 nsLayoutUtils::GetParentOrPlaceholderFor(nsIFrame* aFrame)
 {
   if ((aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
       && !aFrame->GetPrevInFlow()) {
-    return aFrame->PresContext()->PresShell()->FrameManager()->
-      GetPlaceholderFrameFor(aFrame);
+    return aFrame->GetProperty(nsIFrame::PlaceholderFrameProperty());
   }
   return aFrame->GetParent();
 }
 
 nsIFrame*
 nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(nsIFrame* aFrame)
 {
   nsIFrame* f = GetParentOrPlaceholderFor(aFrame);
--- a/layout/generic/ReflowInput.cpp
+++ b/layout/generic/ReflowInput.cpp
@@ -1608,18 +1608,17 @@ ReflowInput::InitAbsoluteConstraints(nsP
   bool bStartIsAuto = styleOffset.GetBStartUnit(cbwm) == eStyleUnit_Auto;
   bool bEndIsAuto   = styleOffset.GetBEndUnit(cbwm) == eStyleUnit_Auto;
 
   // If both 'left' and 'right' are 'auto' or both 'top' and 'bottom' are
   // 'auto', then compute the hypothetical box position where the element would
   // have been if it had been in the flow
   nsHypotheticalPosition hypotheticalPos;
   if ((iStartIsAuto && iEndIsAuto) || (bStartIsAuto && bEndIsAuto)) {
-    nsPlaceholderFrame* placeholderFrame =
-      aPresContext->PresShell()->GetPlaceholderFrameFor(mFrame);
+    nsPlaceholderFrame* placeholderFrame = mFrame->GetPlaceholderFrame();
     MOZ_ASSERT(placeholderFrame, "no placeholder frame");
 
     if (placeholderFrame->HasAnyStateBits(
           PLACEHOLDER_STATICPOS_NEEDS_CSSALIGN)) {
       DebugOnly<nsIFrame*> placeholderParent = placeholderFrame->GetParent();
       MOZ_ASSERT(placeholderParent, "shouldn't have unparented placeholders");
       MOZ_ASSERT(placeholderParent->IsFlexOrGridContainer(),
                  "This flag should only be set on grid/flex children");
--- a/layout/generic/nsAbsoluteContainingBlock.cpp
+++ b/layout/generic/nsAbsoluteContainingBlock.cpp
@@ -377,28 +377,19 @@ nsAbsoluteContainingBlock::DoMarkFramesD
       kidFrame->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
     }
   }
 }
 
 // Given an out-of-flow frame, this method returns the parent frame of
 // its placeholder frame, if that parent is a nsContainerFrame.
 static nsContainerFrame*
-GetPlaceholderContainer(nsPresContext* aPresContext,
-                        nsIFrame* aPositionedFrame)
+GetPlaceholderContainer(nsIFrame* aPositionedFrame)
 {
-  MOZ_ASSERT(aPositionedFrame, "need non-null frame");
-  MOZ_ASSERT(aPositionedFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW),
-             "expecting abspos frame");
-  MOZ_ASSERT(aPresContext && aPresContext == aPositionedFrame->PresContext(),
-             "need non-null pres context which matches our frame");
-
-  nsIFrame* placeholder =
-    aPresContext->PresShell()->GetPlaceholderFrameFor(aPositionedFrame);
-
+  nsIFrame* placeholder = aPositionedFrame->GetPlaceholderFrame();
   if (!placeholder) {
     return nullptr;
   }
   return do_QueryFrame(placeholder->GetParent());
 }
 
 /**
  * This function returns the offset of an abs/fixed-pos child's static
@@ -580,18 +571,17 @@ nsAbsoluteContainingBlock::ResolveSizeDe
     if (NS_AUTOOFFSET == aOffsets->IStart(outerWM)) {
       NS_ASSERTION(NS_AUTOOFFSET != aOffsets->IEnd(outerWM),
                    "Can't solve for both start and end");
       aOffsets->IStart(outerWM) =
         logicalCBSizeOuterWM.ISize(outerWM) -
         aOffsets->IEnd(outerWM) - aMargin.IStartEnd(outerWM) -
         aKidSize.ISize(outerWM);
     } else if (aKidReflowInput.mFlags.mIOffsetsNeedCSSAlign) {
-      placeholderContainer = GetPlaceholderContainer(aPresContext,
-                                                     aKidReflowInput.mFrame);
+      placeholderContainer = GetPlaceholderContainer(aKidReflowInput.mFrame);
       nscoord offset = OffsetToAlignedStaticPos(aKidReflowInput, aKidSize,
                                                 logicalCBSizeOuterWM,
                                                 placeholderContainer,
                                                 outerWM, eLogicalAxisInline);
       // Shift IStart from its current position (at start corner of the
       // alignment container) by the returned offset.  And set IEnd to the
       // distance between the kid's end edge to containing block's end edge.
       aOffsets->IStart(outerWM) += offset;
@@ -602,18 +592,17 @@ nsAbsoluteContainingBlock::ResolveSizeDe
 
     if (NS_AUTOOFFSET == aOffsets->BStart(outerWM)) {
       aOffsets->BStart(outerWM) =
         logicalCBSizeOuterWM.BSize(outerWM) -
         aOffsets->BEnd(outerWM) - aMargin.BStartEnd(outerWM) -
         aKidSize.BSize(outerWM);
     } else if (aKidReflowInput.mFlags.mBOffsetsNeedCSSAlign) {
       if (!placeholderContainer) {
-        placeholderContainer = GetPlaceholderContainer(aPresContext,
-                                                       aKidReflowInput.mFrame);
+        placeholderContainer = GetPlaceholderContainer(aKidReflowInput.mFrame);
       }
       nscoord offset = OffsetToAlignedStaticPos(aKidReflowInput, aKidSize,
                                                 logicalCBSizeOuterWM,
                                                 placeholderContainer,
                                                 outerWM, eLogicalAxisBlock);
       // Shift BStart from its current position (at start corner of the
       // alignment container) by the returned offset.  And set BEnd to the
       // distance between the kid's end edge to containing block's end edge.
@@ -678,18 +667,17 @@ nsAbsoluteContainingBlock::ReflowAbsolut
   uint32_t rsFlags = 0;
   if (aFlags & AbsPosReflowFlags::eIsGridContainerCB) {
     // When a grid container generates the abs.pos. CB for a *child* then
     // the static position is determined via CSS Box Alignment within the
     // abs.pos. CB (a grid area, i.e. a piece of the grid). In this scenario,
     // due to the multiple coordinate spaces in play, we use a convenience flag
     // to simply have the child's ReflowInput give it a static position at its
     // abs.pos. CB origin, and then we'll align & offset it from there.
-    nsIFrame* placeholder =
-      aPresContext->PresShell()->GetPlaceholderFrameFor(aKidFrame);
+    nsIFrame* placeholder = aKidFrame->GetPlaceholderFrame();
     if (placeholder && placeholder->GetParent() == aDelegatingFrame) {
       rsFlags |= ReflowInput::STATIC_POS_IS_CB_ORIGIN;
     }
   }
   ReflowInput kidReflowInput(aPresContext, aReflowInput, aKidFrame,
                                    LogicalSize(wm, availISize,
                                                NS_UNCONSTRAINEDSIZE),
                                    &logicalCBSize, rsFlags);
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -4408,18 +4408,17 @@ static bool
 CheckPlaceholderInLine(nsIFrame* aBlock, nsLineBox* aLine, nsFloatCache* aFC)
 {
   if (!aFC)
     return true;
   NS_ASSERTION(!aFC->mFloat->GetPrevContinuation(),
                "float in a line should never be a continuation");
   NS_ASSERTION(!(aFC->mFloat->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT),
                "float in a line should never be a pushed float");
-  nsIFrame* ph = aBlock->PresContext()->FrameManager()->
-                   GetPlaceholderFrameFor(aFC->mFloat->FirstInFlow());
+  nsIFrame* ph = aFC->mFloat->FirstInFlow()->GetPlaceholderFrame();
   for (nsIFrame* f = ph; f; f = f->GetParent()) {
     if (f->GetParent() == aBlock)
       return aLine->Contains(f);
   }
   NS_ASSERTION(false, "aBlock is not an ancestor of aFrame!");
   return true;
 }
 
@@ -5011,19 +5010,18 @@ nsBlockFrame::DrainSelfPushedFloats()
     }
 
     for (nsIFrame *f = ourPushedFloats->LastChild(), *next; f; f = next) {
       next = f->GetPrevSibling();
 
       if (f->GetPrevContinuation()) {
         // FIXME
       } else {
-        nsPlaceholderFrame *placeholder =
-          presContext->FrameManager()->GetPlaceholderFrameFor(f);
-        nsIFrame *floatOriginalParent = presContext->PresShell()->
+        nsPlaceholderFrame* placeholder = f->GetPlaceholderFrame();
+        nsIFrame* floatOriginalParent = presContext->PresShell()->
           FrameConstructor()->GetFloatContainingBlock(placeholder);
         if (floatOriginalParent != this) {
           // This is a first continuation that was pushed from one of our
           // previous continuations.  Take it out of the pushed floats
           // list and put it in our floats list, before any of our
           // floats, but after other pushed floats.
           ourPushedFloats->RemoveFrame(f);
           mFloats.InsertFrame(nullptr, insertionPrevSibling, f);
@@ -5636,17 +5634,17 @@ FindChildContaining(nsBlockFrame* aFrame
       if (child)
         break;
       block = block->GetNextContinuation();
     } while (block);
     if (!child)
       return nullptr;
     if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW))
       break;
-    aFindFrame = aFrame->PresContext()->FrameManager()->GetPlaceholderFrameFor(child);
+    aFindFrame = child->GetPlaceholderFrame();
   }
 
   return child;
 }
 
 nsBlockInFlowLineIterator::nsBlockInFlowLineIterator(nsBlockFrame* aFrame,
     nsIFrame* aFindFrame, bool* aFoundValidLine)
   : mFrame(aFrame), mLineList(&aFrame->mLines)
@@ -6926,19 +6924,18 @@ nsBlockFrame::ChildIsDirty(nsIFrame* aCh
     // its line dirty when we handle NS_BLOCK_LOOK_FOR_DIRTY_FRAMES.
     // We need to take some care to handle the case where a float is in
     // a different continuation than its placeholder, including marking
     // an extra block with NS_BLOCK_LOOK_FOR_DIRTY_FRAMES.
     if (!(aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
       AddStateBits(NS_BLOCK_LOOK_FOR_DIRTY_FRAMES);
     } else {
       NS_ASSERTION(aChild->IsFloating(), "should be a float");
-      nsIFrame *thisFC = FirstContinuation();
-      nsIFrame *placeholderPath =
-        PresContext()->FrameManager()->GetPlaceholderFrameFor(aChild);
+      nsIFrame* thisFC = FirstContinuation();
+      nsIFrame* placeholderPath = aChild->GetPlaceholderFrame();
       // SVG code sometimes sends FrameNeedsReflow notifications during
       // frame destruction, leading to null placeholders, but we're safe
       // ignoring those.
       if (placeholderPath) {
         for (;;) {
           nsIFrame *parent = placeholderPath->GetParent();
           if (parent->GetContent() == mContent &&
               parent->FirstContinuation() == thisFC) {
--- a/layout/generic/nsFirstLetterFrame.cpp
+++ b/layout/generic/nsFirstLetterFrame.cpp
@@ -310,18 +310,17 @@ nsFirstLetterFrame::CreateContinuationFo
 {
   NS_ASSERTION(IsFloating(),
                "can only call this on floating first letter frames");
   NS_PRECONDITION(aContinuation, "bad args");
 
   *aContinuation = nullptr;
 
   nsIPresShell* presShell = aPresContext->PresShell();
-  nsPlaceholderFrame* placeholderFrame =
-    presShell->FrameManager()->GetPlaceholderFrameFor(this);
+  nsPlaceholderFrame* placeholderFrame = GetPlaceholderFrame();
   nsContainerFrame* parent = placeholderFrame->GetParent();
 
   nsIFrame* continuation = presShell->FrameConstructor()->
     CreateContinuingFrame(aPresContext, aChild, parent, aIsFluid);
 
   // The continuation will have gotten the first letter style from its
   // prev continuation, so we need to repair the style context so it
   // doesn't have the first letter styling.
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -721,18 +721,17 @@ nsFrame::DestroyFrom(nsIFrame* aDestruct
     if (ssc) {
       ssc->RemoveFrame(this);
     }
   }
 
   nsPresContext* presContext = PresContext();
   nsIPresShell* shell = presContext->GetPresShell();
   if (mState & NS_FRAME_OUT_OF_FLOW) {
-    nsPlaceholderFrame* placeholder =
-      shell->FrameManager()->GetPlaceholderFrameFor(this);
+    nsPlaceholderFrame* placeholder = GetPlaceholderFrame();
     NS_ASSERTION(!placeholder || (aDestructRoot != this),
                  "Don't call Destroy() on OOFs, call Destroy() on the placeholder.");
     NS_ASSERTION(!placeholder ||
                  nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, placeholder),
                  "Placeholder relationship should have been torn down already; "
                  "this might mean we have a stray placeholder in the tree.");
     if (placeholder) {
       placeholder->SetOutOfFlowFrame(nullptr);
@@ -8463,32 +8462,31 @@ nsFrame::CheckVisibility(nsPresContext* 
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 
 int32_t
 nsFrame::GetLineNumber(nsIFrame *aFrame, bool aLockScroll, nsIFrame** aContainingBlock)
 {
   NS_ASSERTION(aFrame, "null aFrame");
-  nsFrameManager* frameManager = aFrame->PresContext()->FrameManager();
-  nsIFrame *blockFrame = aFrame;
-  nsIFrame *thisBlock;
+  nsIFrame* blockFrame = aFrame;
+  nsIFrame* thisBlock;
   nsAutoLineIterator it;
   nsresult result = NS_ERROR_FAILURE;
   while (NS_FAILED(result) && blockFrame)
   {
     thisBlock = blockFrame;
     if (thisBlock->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
       //if we are searching for a frame that is not in flow we will not find it. 
       //we must instead look for its placeholder
       if (thisBlock->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
         // abspos continuations don't have placeholders, get the fif
         thisBlock = thisBlock->FirstInFlow();
       }
-      thisBlock = frameManager->GetPlaceholderFrameFor(thisBlock);
+      thisBlock = thisBlock->GetPlaceholderFrame();
       if (!thisBlock)
         return -1;
     }  
     blockFrame = thisBlock->GetParent();
     result = NS_OK;
     if (blockFrame) {
       if (aLockScroll && blockFrame->IsScrollFrame())
         return -1;
@@ -9423,33 +9421,33 @@ nsFrame::CorrectStyleParentFrame(nsIFram
                "Should have found a parent before this");
   return nullptr;
 }
 
 nsStyleContext*
 nsFrame::DoGetParentStyleContext(nsIFrame** aProviderFrame) const
 {
   *aProviderFrame = nullptr;
-  nsFrameManager* fm = PresContext()->FrameManager();
 
   // Handle display:contents and the root frame, when there's no parent frame
   // to inherit from.
   if (MOZ_LIKELY(mContent)) {
     nsIContent* parentContent = mContent->GetFlattenedTreeParent();
     if (MOZ_LIKELY(parentContent)) {
       nsIAtom* pseudo = StyleContext()->GetPseudo();
       if (!pseudo || !mContent->IsElement() ||
           (!nsCSSAnonBoxes::IsAnonBox(pseudo) &&
            // Ensure that we don't return the display:contents style
            // of the parent content for pseudos that have the same content
            // as their primary frame (like -moz-list-bullets do):
            mContent->GetPrimaryFrame() == this) ||
           /* if next is true then it's really a request for the table frame's
              parent context, see nsTable[Outer]Frame::GetParentStyleContext. */
           pseudo == nsCSSAnonBoxes::tableWrapper) {
+        nsFrameManager* fm = PresContext()->FrameManager();
         nsStyleContext* sc = fm->GetDisplayContentsStyleFor(parentContent);
         if (MOZ_UNLIKELY(sc)) {
           return sc;
         }
       }
     } else {
       if (!StyleContext()->GetPseudo()) {
         // we're a frame for the root.  We have no style context parent.
@@ -9476,17 +9474,17 @@ nsFrame::DoGetParentStyleContext(nsIFram
     // frame would have if we didn't mangle the frame structure.
     *aProviderFrame = GetCorrectedParent(this);
     return *aProviderFrame ? (*aProviderFrame)->StyleContext() : nullptr;
   }
 
   // We're an out-of-flow frame.  For out-of-flow frames, we must
   // resolve underneath the placeholder's parent.  The placeholder is
   // reached from the first-in-flow.
-  nsPlaceholderFrame* placeholder = fm->GetPlaceholderFrameFor(FirstInFlow());
+  nsPlaceholderFrame* placeholder = FirstInFlow()->GetPlaceholderFrame();
   if (!placeholder) {
     NS_NOTREACHED("no placeholder frame for out-of-flow frame");
     *aProviderFrame = GetCorrectedParent(this);
     return *aProviderFrame ? (*aProviderFrame)->StyleContext() : nullptr;
   }
   return placeholder->GetParentStyleContextForOutOfFlow(aProviderFrame);
 }
 
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -832,16 +832,26 @@ public:
 
   /**
    * Gets the parent of a frame, using the parent of the placeholder for
    * out-of-flow frames.
    */
   inline nsContainerFrame* GetInFlowParent();
 
   /**
+   * Return the placeholder for this frame (which must be out-of-flow).
+   * @note this will only return non-null if |this| is the first-in-flow
+   * although we don't assert that here for legacy reasons.
+   */
+  inline nsPlaceholderFrame* GetPlaceholderFrame() const {
+    MOZ_ASSERT(HasAnyStateBits(NS_FRAME_OUT_OF_FLOW));
+    return GetProperty(PlaceholderFrameProperty());
+  }
+
+  /**
    * Set this frame's parent to aParent.
    * If the frame may have moved into or out of a scrollframe's
    * frame subtree, StickyScrollContainer::NotifyReparentedFrameAcrossScrollFrameBoundary
    * must also be called.
    */
   void SetParent(nsContainerFrame* aParent);
 
   /**
--- a/layout/generic/nsIFrameInlines.h
+++ b/layout/generic/nsIFrameInlines.h
@@ -168,16 +168,16 @@ nsIFrame::PropagateRootElementWritingMod
     f->mWritingMode = aRootElemWM;
   }
 }
 
 nsContainerFrame*
 nsIFrame::GetInFlowParent()
 {
   if (GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
-    nsFrameManager* fm = PresContext()->FrameManager();
-    return fm->GetPlaceholderFrameFor(FirstContinuation())->GetParent();
+    nsIFrame* ph = FirstContinuation()->GetProperty(nsIFrame::PlaceholderFrameProperty());
+    return ph->GetParent();
   }
 
   return GetParent();
 }
 
 #endif
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -1381,18 +1381,17 @@ BuildTextRuns(DrawTarget* aDrawTarget, n
 {
   MOZ_ASSERT(aForFrame, "for no frame?");
   NS_ASSERTION(!aForFrameLine || aLineContainer,
                "line but no line container");
 
   nsIFrame* lineContainerChild = aForFrame;
   if (!aLineContainer) {
     if (aForFrame->IsFloatingFirstLetterChild()) {
-      lineContainerChild = aForFrame->PresContext()->PresShell()->
-        GetPlaceholderFrameFor(aForFrame->GetParent());
+      lineContainerChild = aForFrame->GetParent()->GetPlaceholderFrame();
     }
     aLineContainer = FindLineContainer(lineContainerChild);
   } else {
     NS_ASSERTION((aLineContainer == FindLineContainer(aForFrame) ||
                   (aLineContainer->IsLetterFrame() &&
                    aLineContainer->IsFloating())),
                  "Wrong line container hint");
   }