Relative positioning for column-span fix draft
authorNeerja Pancholi <npancholi@mozilla.com>
Fri, 20 Oct 2017 18:41:26 -0700
changeset 698702 f7d592679711081a3e7da2fab78934880b986d37
parent 698701 353e1785c714a861cbb65e9899b7f1634696fee2
child 698703 9a3d51b58a4f98c52db511e88dfc94f7bcd8c372
push id89334
push userbmo:npancholi@mozilla.com
push dateThu, 16 Nov 2017 00:39:30 +0000
milestone59.0a1
Relative positioning for column-span fix MozReview-Commit-ID: G2TY2CRM8Xc
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
layout/generic/nsBlockFrame.cpp
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -928,16 +928,21 @@ public:
                           nsContainerFrame* aFloatContainingBlock);
 
   ~nsFrameConstructorState();
 
   bool HasAncestorFilter()
   {
     return mTreeMatchContext && mTreeMatchContext->mAncestorFilter.HasFilter();
   }
+  
+  // xxxNeerja - write comment
+  void OverwriteAbsoluteState(nsContainerFrame*            aNewAbsoluteContainingBlock,
+                              nsFrameList&                 aSplitAbsoluteList,
+                              nsFrameConstructorSaveState& aAbsoluteSaveState);
 
   // Function to push the existing absolute containing block state and
   // create a new scope. Code that uses this function should get matching
   // logic in GetAbsoluteContainingBlock.
   // Also makes aNewAbsoluteContainingBlock the containing block for
   // fixed-pos elements if necessary.
   // aPositionedFrame is the frame whose style actually makes
   // aNewAbsoluteContainingBlock a containing block. E.g. for a scrollable element
@@ -1001,17 +1006,21 @@ public:
   nsAbsoluteItems& GetFixedItems()
   {
     return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
   }
   const nsAbsoluteItems& GetFixedItems() const
   {
     return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
   }
-
+    
+  nsAbsoluteItems& GetAbsoluteItems()
+  {
+      return mAbsoluteItems;
+  }
 
   /**
    * class to automatically push and pop a pending binding in the frame
    * constructor state.  See nsCSSFrameConstructor::FrameConstructionItem
    * mPendingBinding documentation.
    */
   class PendingBindingAutoPusher;
   friend class PendingBindingAutoPusher;
@@ -1170,16 +1179,55 @@ AdjustAbsoluteContainingBlock(nsContaine
   }
 
   // Always use the container's first continuation. (Inline frames can have
   // non-fluid bidi continuations...)
   return static_cast<nsContainerFrame*>(aContainingBlockIn->FirstContinuation());
 }
 
 void
+nsFrameConstructorState::OverwriteAbsoluteState(nsContainerFrame*            aNewAbsoluteContainingBlock,
+                                                nsFrameList&                 aSplitAbsoluteList,
+                                                nsFrameConstructorSaveState& aSaveState)
+{
+  // First overwrite the original state and then save it in aSaveState
+  mAbsoluteItems = nsAbsoluteItems(AdjustAbsoluteContainingBlock(aNewAbsoluteContainingBlock));
+  while (aSplitAbsoluteList.NotEmpty()) {
+    mAbsoluteItems.AddChild(aSplitAbsoluteList.RemoveFirstChild());
+  }
+//
+//  /* See if we're wiring the fixed-pos and abs-pos lists together.  This happens iff
+//   * we're a transformed element.
+//   */
+//  mFixedPosIsAbsPos = aNewAbsoluteContainingBlock &&
+//    aNewAbsoluteContainingBlock->IsFixedPosContainingBlock();
+//
+//  if (aNewAbsoluteContainingBlock) {
+//    aNewAbsoluteContainingBlock->MarkAsAbsoluteContainingBlock();
+//  }
+//
+//  aSaveState.mItems->containingBlock = AdjustAbsoluteContainingBlock(aNewAbsoluteContainingBlock);
+//  while (aSplitAbsoluteList.NotEmpty()) {
+//    aSaveState.mItems->AddChild(aSplitAbsoluteList.RemoveFirstChild());
+//  }
+//  aSaveState.mSavedItems = aSaveState.mItems;
+//  aSaveState.mChildListID = nsIFrame::kAbsoluteList;
+//  aSaveState.mState = this;
+//  aSaveState.mSavedFixedPosIsAbsPos = aNewAbsoluteContainingBlock &&
+//    aNewAbsoluteContainingBlock->IsFixedPosContainingBlock();;
+
+  //xxxNeerja - Do we need to do this?
+//  if (mFixedPosIsAbsPos) {
+//    aSaveState.mSavedFixedItems = mFixedItems;
+//    mFixedItems = mAbsoluteItems;
+//  }
+  
+}
+
+void
 nsFrameConstructorState::PushAbsoluteContainingBlock(nsContainerFrame* aNewAbsoluteContainingBlock,
                                                      nsIFrame* aPositionedFrame,
                                                      nsFrameConstructorSaveState& aSaveState)
 {
   aSaveState.mItems = &mAbsoluteItems;
   aSaveState.mSavedItems = mAbsoluteItems;
   aSaveState.mChildListID = nsIFrame::kAbsoluteList;
   aSaveState.mState = this;
@@ -12360,60 +12408,54 @@ ProcessColumnSpan(nsFrameConstructorStat
   if ((*aNewFrame)->Type() != LayoutFrameType::ColumnSetWrapper) {
     MOZ_ASSERT(grandParent->Type() != LayoutFrameType::ColumnSetWrapper,
                 "Grandparent cannot be columnSetWrapper! In that case newFrame==gparent");
 
     nsFrameItems splitChildren;
     SplitBlocks(aState, aOldParent, aChildItems, splitChildren);
     MOZ_ASSERT(splitChildren.NotEmpty(), "Child items cannot be empty here!");
 
-    // Clean up the aOldParent and its placeholder, if present
     aFrameItems.RemoveFrame(aOldParent);
     //aOldParent is guaranteed to be a block here
     nsBlockFrame* oldBlockParent = static_cast<nsBlockFrame*>(aOldParent);
     oldBlockParent->TransferFloats();
-    aOldParent->Destroy();
-
+    
     *aNewFrame = static_cast<nsContainerFrame*>(splitChildren.FirstChild());
     while (splitChildren.NotEmpty()) {
       nsContainerFrame* currChild =
           static_cast<nsContainerFrame*>(splitChildren.RemoveFirstChild());
       aState.AddChild(currChild, aFrameItems, content, styleContext, aFinalParent);
-
-      // We should make the outer frame be the absolute containing block,
-      // if one is required. We have to do this because absolute
-      // positioning must be computed with respect to the CSS dimensions
-      // of the element, which are the dimensions of the outer block. But
-      // we can't really do that because only blocks can have absolute
-      // children. So use the block and try to compensate with hacks
-      // in nsBlockFrame::CalculateContainingBlockSizeForAbsolutes.
-      nsFrameConstructorSaveState absoluteSaveState;
-      currChild->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
-      if (aPositionedFrameForAbsPosContainer) {
-        aState.PushAbsoluteContainingBlock(currChild,
-                                           aPositionedFrameForAbsPosContainer,
-                                           absoluteSaveState);
+        
+      if (aPositionedFrameForAbsPosContainer &&
+          aPositionedFrameForAbsPosContainer == aOldParent) {
+          nsFrameList splitAbsoluteList;
+          SplitAbsoluteListForSplitBlock(currChild, aState.GetAbsoluteItems(), splitAbsoluteList);
+          nsFrameConstructorSaveState absoluteSaveState;
+          currChild->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
+          aState.OverwriteAbsoluteState(currChild, splitAbsoluteList, absoluteSaveState);
+        aState.PushAbsoluteContainingBlock(currChild, currChild, absoluteSaveState);
       }
     }
   } else {
     nsFrameItems finalChildItems;
     WrapNonSpannerChildrenInColumnSets(aState, aOldParent, aChildItems,
                                        finalChildItems);
     MOZ_ASSERT(finalChildItems.NotEmpty(), "Child items cannot be empty here!");
 
     // aOldParent is guaranteed to be a block here
     nsBlockFrame* oldBlockParent = static_cast<nsBlockFrame*>(aOldParent);
     oldBlockParent->TransferFloats();
 
     MoveChildrenTo(aOldParent, grandParent, finalChildItems);
 
     // Clean up the aOldParent
     // Note: In this case aOldParent was never added to aFrameItems
-    aOldParent->Destroy();
-  }
+    //aOldParent->Destroy();
+  }
+  aOldParent->Destroy();
 }
 
 void
 nsCSSFrameConstructor::SplitBlocks(nsFrameConstructorState& aState,
                                    nsContainerFrame*        aOldParent,
                                    nsFrameList&             aUnsplitChildItems,
                                    nsFrameItems&            aSplitChildItems,
                                    nsStyleContext*          aNonSpannerSC)
@@ -12521,16 +12563,44 @@ WrapNonSpannerChildrenInColumnSets(nsFra
   }
 
   // Note: Because of this function, column-span wrappers and ColumnSetFrame
   // wrappers are not ib-siblings of each other since we create columnSetFrames
   // as one additional wrapper around non-spanning elements and this would upset
   // the IB-sibling chain.
 }
 
+void
+nsCSSFrameConstructor::SplitAbsoluteListForSplitBlock(nsContainerFrame* aSplitFrame,
+                                                      nsAbsoluteItems&  aOriginalAbsoluteList,
+                                                      nsFrameList&      aSplitAbsoluteList)
+{
+  for (nsIFrame* currAbsoluteFrame = aOriginalAbsoluteList.FirstChild(); currAbsoluteFrame != nullptr;) {
+      nsIFrame* placeholder = currAbsoluteFrame->GetPlaceholderFrame();
+      if (placeholder) {
+        // Check if this placeholder is a descendent of aSplitFrame, if it is then move its OOF
+        // into the splitAbsoluteList
+        nsIFrame* parent = placeholder->GetParent();
+        while (parent && parent != aSplitFrame) {
+          parent = parent->GetParent();
+        }
+        if (parent) {
+          nsIFrame* nextAbsoluteFrame = currAbsoluteFrame->GetNextSibling();
+          aOriginalAbsoluteList.RemoveFrame(currAbsoluteFrame);
+          
+          // xxxNeerja - Do I need to reparent these absolute frames??
+          aSplitAbsoluteList.AppendFrame(nullptr, currAbsoluteFrame);
+          currAbsoluteFrame = nextAbsoluteFrame;
+        }
+      } else {
+        NS_WARNING("An OOF exists with a null placeholder!");
+      }
+    }
+}
+
 nsIFrame*
 nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState& aState,
                                        FrameConstructionItem&   aItem,
                                        nsContainerFrame*        aParentFrame,
                                        const nsStyleDisplay*    aDisplay,
                                        nsFrameItems&            aFrameItems)
 {
   // If an inline frame has non-inline kids, then we chop up the child list
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -34,16 +34,17 @@ struct nsGenConInitializer;
 class nsContainerFrame;
 class nsFirstLineFrame;
 class nsFirstLetterFrame;
 class nsICSSAnonBoxPseudo;
 class nsIDocument;
 class nsPageContentFrame;
 struct PendingBinding;
 class nsGenericDOMDataNode;
+struct nsAbsoluteItems;
 
 class nsFrameConstructorState;
 
 namespace mozilla {
 
 namespace dom {
 
 class FlattenedChildIterator;
@@ -1962,16 +1963,20 @@ private:
    * Create ColumnSetFrames around any consecutive non-spanning elements
    * present in aInitialChildItems. Let the spanning items stay as is and return
    * this new list in aFinalChildItems.
    */
   void WrapNonSpannerChildrenInColumnSets(nsFrameConstructorState& aState,
                                           nsContainerFrame*        aOldParent,
                                           nsFrameItems&            aInitialChildItems,
                                           nsFrameItems&            aFinalChildItems);
+  
+  void SplitAbsoluteListForSplitBlock(nsContainerFrame* aSplitFrame,
+                                      nsAbsoluteItems&  aOriginalAbsoluteList,
+                                      nsFrameList&      aSplitAbsoluteList);
 
   // |aContentParentFrame| should be null if it's really the same as
   // |aParentFrame|.
   // @param aFrameItems where we want to put the block in case it's in-flow.
   // @param aNewFrame an in/out parameter. On input it is the block to be
   // constructed. On output it is reset to the outermost
   // frame constructed (e.g. if we need to wrap the block in an
   // nsColumnSetFrame.
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -5701,18 +5701,17 @@ nsBlockFrame::TransferFloats()
       currFloat->SetParent(finalBlockParent);
       nsFrameList temp(currFloat, currFloat);
       finalBlockParent->AppendFrames(nsIFrame::kFloatList, temp);
 
       currFloat = nextFloat;
       if (nextFloat) {
         nextFloat = nextFloat->GetNextSibling();
       }
-    }
-    else {
+    } else {
       NS_WARNING("An OOF exists with a null placeholder!");
     }
   }
 }
 
 static nsIFrame*
 FindChildContaining(nsBlockFrame* aFrame, nsIFrame* aFindFrame)
 {