Bug 976365 - Make 'perspective' create a containing block for absolute and fixed positioned children. r=dbaron
authorMatt Woodrow <mwoodrow@mozilla.com>
Tue, 25 Mar 2014 11:45:43 +1300
changeset 175114 8dafd4b9969a0aba78e2376625b32901f40d5550
parent 175113 9402c13b1475394616e4ec909024373965b223d0
child 175115 4d5074dfad5d0a43fb07cd9a9139500d4b9fcce0
push id41435
push usermwoodrow@mozilla.com
push dateMon, 24 Mar 2014 22:45:57 +0000
treeherdermozilla-inbound@8dafd4b9969a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs976365
milestone31.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 976365 - Make 'perspective' create a containing block for absolute and fixed positioned children. r=dbaron
layout/base/nsCSSFrameConstructor.cpp
layout/generic/nsFrame.cpp
layout/style/nsStyleStruct.h
layout/style/nsStyleStructInlines.h
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -1008,17 +1008,18 @@ nsFrameConstructorState::PushAbsoluteCon
 
   mAbsoluteItems =
     nsAbsoluteItems(AdjustAbsoluteContainingBlock(aNewAbsoluteContainingBlock));
 
   /* See if we're wiring the fixed-pos and abs-pos lists together.  This happens iff
    * we're a transformed element.
    */
   mFixedPosIsAbsPos = aPositionedFrame &&
-      aPositionedFrame->StyleDisplay()->HasTransform(aPositionedFrame);
+      (aPositionedFrame->StyleDisplay()->HasTransform(aPositionedFrame) ||
+       aPositionedFrame->StyleDisplay()->HasPerspectiveStyle());
 
   if (aNewAbsoluteContainingBlock) {
     aNewAbsoluteContainingBlock->MarkAsAbsoluteContainingBlock();
   }
 }
 
 void
 nsFrameConstructorState::PushFloatContainingBlock(nsIFrame* aNewFloatContainingBlock,
@@ -1946,21 +1947,17 @@ nsCSSFrameConstructor::ConstructTable(ns
   nsFrameItems childItems;
 
   // Process children
   nsFrameConstructorSaveState absoluteSaveState;
   const nsStyleDisplay* display = outerStyleContext->StyleDisplay();
 
   // Mark the table frame as an absolute container if needed
   newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
-  if ((display->IsRelativelyPositionedStyle() ||
-       display->IsAbsolutelyPositionedStyle() ||
-       (display->HasTransformStyle() &&
-        aParentFrame->IsFrameOfType(nsIFrame::eSupportsCSSTransforms))) &&
-      !aParentFrame->IsSVGText()) {
+  if (display->IsPositioned(newFrame)) {
     aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
   }
   NS_ASSERTION(aItem.mAnonChildren.IsEmpty(),
                "nsIAnonymousContentCreator::CreateAnonymousContent "
                "implementations for table frames are not currently expected "
                "to output a list where the items have their own children");
   if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
     ConstructFramesFromItemList(aState, aItem.mChildItems,
@@ -1993,19 +1990,17 @@ MakeTablePartAbsoluteContainingBlockIfNe
   // If we're positioned, then we need to become an absolute containing block
   // for any absolutely positioned children and register for post-reflow fixup.
   //
   // Note that usually if a frame type can be an absolute containing block, we
   // always set NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN, whether it actually is or not.
   // However, in this case flag serves the additional purpose of indicating that
   // the frame was registered with its table frame. This allows us to avoid the
   // overhead of unregistering the frame in most cases.
-  if (aDisplay->IsRelativelyPositionedStyle() ||
-      aDisplay->IsAbsolutelyPositionedStyle() ||
-      aDisplay->HasTransform(aFrame)) {
+  if (aDisplay->IsPositioned(aFrame)) {
     aFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
     aState.PushAbsoluteContainingBlock(aFrame, aFrame, aAbsSaveState);
     nsTableFrame::RegisterPositionedTablePart(aFrame);
   }
 }
 
 nsIFrame*
 nsCSSFrameConstructor::ConstructTableRowOrRowGroup(nsFrameConstructorState& aState,
@@ -3705,20 +3700,25 @@ nsCSSFrameConstructor::ConstructFrameFro
     nsFrameItems childItems;
     nsFrameConstructorSaveState absoluteSaveState;
 
     if (bits & FCDATA_FORCE_NULL_ABSPOS_CONTAINER) {
       aState.PushAbsoluteContainingBlock(nullptr, nullptr, absoluteSaveState);
     } else if (!(bits & FCDATA_SKIP_ABSPOS_PUSH)) {
       nsIFrame* cb = maybeAbsoluteContainingBlock;
       cb->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
+      // This check is identical to nsStyleDisplay::IsPositioned except without
+      // the assertion that the style display and frame match. When constructing
+      // scroll frames we intentionally use the style display for the outer, but
+      // make the inner the containing block.
       if ((maybeAbsoluteContainingBlockDisplay->IsAbsolutelyPositionedStyle() ||
            maybeAbsoluteContainingBlockDisplay->IsRelativelyPositionedStyle() ||
            (maybeAbsoluteContainingBlockDisplay->HasTransformStyle() &&
-            cb->IsFrameOfType(nsIFrame::eSupportsCSSTransforms))) &&
+            cb->IsFrameOfType(nsIFrame::eSupportsCSSTransforms)) ||
+           maybeAbsoluteContainingBlockDisplay->HasPerspectiveStyle()) &&
           !cb->IsSVGText()) {
         aState.PushAbsoluteContainingBlock(cb, cb, absoluteSaveState);
       }
     }
 
     if (!aItem.mAnonChildren.IsEmpty()) {
       NS_ASSERTION(!(bits & FCDATA_USE_CHILD_ITEMS),
                    "We should not have both anonymous and non-anonymous "
@@ -5671,17 +5671,19 @@ nsCSSFrameConstructor::GetAbsoluteContai
     // block (see the exceptions below).  Otherwise, we'll start looking at the
     // parent frame, unless we're dealing with a scrollframe.
     // Scrollframes are special since they're not positioned, but their
     // scrolledframe might be.  So, we need to check this special case to return
     // the correct containing block (the scrolledframe) in that case.
     // If we're looking for a fixed-pos containing block and the frame is
     // not transformed, skip it.
     if (!frame->IsPositioned() ||
-        (aType == FIXED_POS && !frame->StyleDisplay()->HasTransform(frame))) {
+        (aType == FIXED_POS &&
+         !frame->StyleDisplay()->HasTransform(frame) &&
+         !frame->StyleDisplay()->HasPerspectiveStyle())) {
       continue;
     }
     nsIFrame* absPosCBCandidate = frame;
     nsIAtom* type = absPosCBCandidate->GetType();
     if (type == nsGkAtoms::fieldSetFrame) {
       absPosCBCandidate = static_cast<nsFieldSetFrame*>(absPosCBCandidate)->GetInner();
       if (!absPosCBCandidate) {
         continue;
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1141,18 +1141,17 @@ nsIFrame::HasPerspective() const
   }
   const nsStyleDisplay* parentDisp = parentStyleContext->StyleDisplay();
   return parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord;
 }
 
 bool
 nsIFrame::ChildrenHavePerspective() const
 {
-  const nsStyleDisplay *disp = StyleDisplay();
-  return disp->mChildPerspective.GetUnit() == eStyleUnit_Coord;
+  return StyleDisplay()->HasPerspectiveStyle();
 }
 
 nsRect
 nsIFrame::GetContentRectRelativeToSelf() const
 {
   nsMargin bp(GetUsedBorderAndPadding());
   ApplySkipSides(bp);
   nsRect r(0, 0, mRect.width, mRect.height);
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -2030,16 +2030,20 @@ struct nsStyleDisplay {
   /* Returns whether the element has the -moz-transform property
    * or a related property. */
   bool HasTransformStyle() const {
     return mSpecifiedTransform != nullptr ||
            mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D ||
            (mWillChangeBitField & NS_STYLE_WILL_CHANGE_TRANSFORM);
   }
 
+  bool HasPerspectiveStyle() const {
+    return mChildPerspective.GetUnit() == eStyleUnit_Coord;
+  }
+
   bool BackfaceIsHidden() const {
     return mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN;
   }
 
   // These are defined in nsStyleStructInlines.h.
 
   // The aContextFrame argument on each of these is the frame this
   // style struct is for.  If the frame is for SVG text, the return
--- a/layout/style/nsStyleStructInlines.h
+++ b/layout/style/nsStyleStructInlines.h
@@ -127,17 +127,18 @@ nsStyleDisplay::HasTransform(const nsIFr
 
 bool
 nsStyleDisplay::IsPositioned(const nsIFrame* aContextFrame) const
 {
   NS_ASSERTION(aContextFrame->StyleDisplay() == this,
                "unexpected aContextFrame");
   return (IsAbsolutelyPositionedStyle() ||
           IsRelativelyPositionedStyle() ||
-          HasTransform(aContextFrame)) &&
+          HasTransform(aContextFrame) ||
+          HasPerspectiveStyle()) &&
          !aContextFrame->IsSVGText();
 }
 
 bool
 nsStyleDisplay::IsRelativelyPositioned(const nsIFrame* aContextFrame) const
 {
   NS_ASSERTION(aContextFrame->StyleDisplay() == this, "unexpected aContextFrame");
   return IsRelativelyPositionedStyle() && !aContextFrame->IsSVGText();