Bug 1064843 part 10 - Create and render backdrop frame for top layer frames. r=dbaron
authorXidorn Quan <quanxunzhen@gmail.com>
Thu, 28 Jan 2016 10:11:00 +1100
changeset 282024 96460bf88fb3ec6cc3a2e1bd62fff5ce32db58ac
parent 282023 c611f24fd6d0f5a880ef0452d75164cfa65e477d
child 282025 968b6c59246546ba734f02370144ee960185b2b8
push id17275
push usercbook@mozilla.com
push dateThu, 28 Jan 2016 11:37:27 +0000
treeherderfx-team@e2d11e2d506c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs1064843
milestone47.0a1
Bug 1064843 part 10 - Create and render backdrop frame for top layer frames. r=dbaron
layout/base/RestyleManager.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
layout/generic/nsContainerFrame.cpp
layout/generic/nsViewportFrame.cpp
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -2328,24 +2328,29 @@ GetNextContinuationWithSameStyle(nsIFram
     }
   }
   return nextContinuation;
 }
 
 nsresult
 RestyleManager::ReparentStyleContext(nsIFrame* aFrame)
 {
-  if (nsGkAtoms::placeholderFrame == aFrame->GetType()) {
+  nsIAtom* frameType = aFrame->GetType();
+  if (frameType == nsGkAtoms::placeholderFrame) {
     // Also reparent the out-of-flow and all its continuations.
     nsIFrame* outOfFlow =
       nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
     NS_ASSERTION(outOfFlow, "no out-of-flow frame");
     do {
       ReparentStyleContext(outOfFlow);
     } while ((outOfFlow = outOfFlow->GetNextContinuation()));
+  } else if (frameType == nsGkAtoms::backdropFrame) {
+    // Style context of backdrop frame has no parent style context, and
+    // thus we do not need to reparent it.
+    return NS_OK;
   }
 
   // DO NOT verify the style tree before reparenting.  The frame
   // tree has already been changed, so this check would just fail.
   nsStyleContext* oldContext = aFrame->StyleContext();
 
   RefPtr<nsStyleContext> newContext;
   nsIFrame* providerFrame;
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -83,16 +83,17 @@
 #include "nsBlockFrame.h"
 #include "nsCanvasFrame.h"
 #include "nsFirstLetterFrame.h"
 #include "nsGfxScrollFrame.h"
 #include "nsPageFrame.h"
 #include "nsSimplePageSequenceFrame.h"
 #include "nsTableOuterFrame.h"
 #include "nsIScrollableFrame.h"
+#include "nsBackdropFrame.h"
 #include "nsTransitionManager.h"
 
 #ifdef MOZ_XUL
 #include "nsIRootBox.h"
 #endif
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
@@ -1209,16 +1210,25 @@ nsFrameConstructorState::AddChild(nsIFra
                                                        parentContext,
                                                        aParentFrame,
                                                        nullptr,
                                                        placeholderType);
 
     placeholderFrame->AddStateBits(mAdditionalStateBits);
     // Add the placeholder frame to the flow
     aFrameItems.AddChild(placeholderFrame);
+
+    if (placeholderType == PLACEHOLDER_FOR_TOPLAYER) {
+      nsIFrame* backdropFrame = nsCSSFrameConstructor::
+        CreateBackdropFrameFor(mPresShell, aContent, aNewFrame,
+                               outOfFlowFrameItems->containingBlock);
+      if (backdropFrame) {
+        frameItems->AddChild(backdropFrame);
+      }
+    }
   }
 #ifdef DEBUG
   else {
     NS_ASSERTION(aNewFrame->GetParent() == aParentFrame,
                  "In-flow frame has wrong parent");
   }
 #endif
 
@@ -2927,16 +2937,48 @@ nsCSSFrameConstructor::CreatePlaceholder
   aFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
 
   // Add mapping from absolutely positioned frame to its placeholder frame
   aPresShell->FrameManager()->RegisterPlaceholderFrame(placeholderFrame);
 
   return placeholderFrame;
 }
 
+/* static */ nsIFrame*
+nsCSSFrameConstructor::CreateBackdropFrameFor(nsIPresShell* aPresShell,
+                                              nsIContent* aContent,
+                                              nsIFrame* aFrame,
+                                              nsContainerFrame* aParentFrame)
+{
+  MOZ_ASSERT(aFrame->StyleDisplay()->mTopLayer == NS_STYLE_TOP_LAYER_TOP);
+  nsContainerFrame* frame = do_QueryFrame(aFrame);
+  if (!frame) {
+    NS_WARNING("Cannot create backdrop frame for non-container frame");
+    return nullptr;
+  }
+
+  RefPtr<nsStyleContext> style = aPresShell->StyleSet()->
+    ResolvePseudoElementStyle(aContent->AsElement(),
+                              nsCSSPseudoElements::ePseudo_backdrop,
+                              /* aParentStyleContext */ nullptr,
+                              /* aPseudoElement */ nullptr);
+  nsBackdropFrame* backdropFrame = new (aPresShell) nsBackdropFrame(style);
+  backdropFrame->Init(aContent, aParentFrame, nullptr);
+
+  nsIFrame* placeholder = CreatePlaceholderFrameFor(aPresShell, aContent,
+                                                    backdropFrame,
+                                                    frame->StyleContext(),
+                                                    frame, nullptr,
+                                                    PLACEHOLDER_FOR_TOPLAYER);
+  nsFrameList temp(placeholder, placeholder);
+  frame->SetInitialChildList(nsIFrame::kBackdropList, temp);
+
+  return backdropFrame;
+}
+
 // 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
 // for the existing children again.
 static inline void
 ClearLazyBits(nsIContent* aStartContent, nsIContent* aEndContent)
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -1270,16 +1270,21 @@ protected:
   static nsIFrame* CreatePlaceholderFrameFor(nsIPresShell*     aPresShell,
                                              nsIContent*       aContent,
                                              nsIFrame*         aFrame,
                                              nsStyleContext*   aParentStyle,
                                              nsContainerFrame* aParentFrame,
                                              nsIFrame*         aPrevInFlow,
                                              nsFrameState      aTypeBit);
 
+  static nsIFrame* CreateBackdropFrameFor(nsIPresShell* aPresShell,
+                                          nsIContent* aContent,
+                                          nsIFrame* aFrame,
+                                          nsContainerFrame* aParentFrame);
+
 private:
   // ConstructSelectFrame puts the new frame in aFrameItems and
   // handles the kids of the select.
   nsIFrame* ConstructSelectFrame(nsFrameConstructorState& aState,
                                  FrameConstructionItem&   aItem,
                                  nsContainerFrame*        aParentFrame,
                                  const nsStyleDisplay*    aStyleDisplay,
                                  nsFrameItems&            aFrameItems);
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -22,16 +22,17 @@
 #include "nsIWidget.h"
 #include "nsCSSRendering.h"
 #include "nsError.h"
 #include "nsDisplayList.h"
 #include "nsIBaseWindow.h"
 #include "nsBoxLayoutState.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsBlockFrame.h"
+#include "nsPlaceholderFrame.h"
 #include "mozilla/AutoRestore.h"
 #include "nsIFrameInlines.h"
 #include "nsPrintfCString.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::layout;
@@ -72,16 +73,27 @@ nsContainerFrame::SetInitialChildList(Ch
     mFrames.SetFrames(aChildList);
   } else if (aListID == kBackdropList) {
     MOZ_ASSERT(StyleDisplay()->mTopLayer != NS_STYLE_TOP_LAYER_NONE,
                "Only top layer frames should have backdrop");
     MOZ_ASSERT(GetStateBits() & NS_FRAME_OUT_OF_FLOW,
                "Top layer frames should be out-of-flow");
     MOZ_ASSERT(!Properties().Get(BackdropProperty()),
                "We shouldn't have setup backdrop frame list before");
+#ifdef DEBUG
+    {
+      nsIFrame* placeholder = aChildList.FirstChild();
+      MOZ_ASSERT(aChildList.OnlyChild(), "Should have only one backdrop");
+      MOZ_ASSERT(placeholder->GetType() == nsGkAtoms::placeholderFrame,
+                "The frame to be stored should be a placeholder");
+      MOZ_ASSERT(static_cast<nsPlaceholderFrame*>(placeholder)->
+                GetOutOfFlowFrame()->GetType() == nsGkAtoms::backdropFrame,
+                "The placeholder should points to a backdrop frame");
+    }
+#endif
     nsFrameList* list =
       new (PresContext()->PresShell()) nsFrameList(aChildList);
     Properties().Set(BackdropProperty(), list);
   } else {
     MOZ_ASSERT_UNREACHABLE("Unexpected child list");
   }
 }
 
--- a/layout/generic/nsViewportFrame.cpp
+++ b/layout/generic/nsViewportFrame.cpp
@@ -136,16 +136,24 @@ ViewportFrame::BuildDisplayListForTopLay
       // elements are not allowed to be out-of-flow. They should not
       // be handled as top layer element here.
       if (!(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
         MOZ_ASSERT(!elem->GetParent()->IsHTMLElement(), "HTML element "
                    "should always be out-of-flow if in the top layer");
         continue;
       }
       MOZ_ASSERT(frame->GetParent() == this);
+      if (nsIFrame* backdropPh =
+          frame->GetChildList(kBackdropList).FirstChild()) {
+        MOZ_ASSERT(backdropPh->GetType() == nsGkAtoms::placeholderFrame);
+        nsIFrame* backdropFrame =
+          static_cast<nsPlaceholderFrame*>(backdropPh)->GetOutOfFlowFrame();
+        MOZ_ASSERT(backdropFrame);
+        BuildDisplayListForTopLayerFrame(aBuilder, backdropFrame, aList);
+      }
       BuildDisplayListForTopLayerFrame(aBuilder, frame, aList);
     }
   }
 
   nsIPresShell* shell = PresContext()->PresShell();
   if (nsCanvasFrame* canvasFrame = shell->GetCanvasFrame()) {
     if (Element* container = canvasFrame->GetCustomContentContainer()) {
       if (nsIFrame* frame = container->GetPrimaryFrame()) {