Bug 844178 - Make RecomputePosition adjust the CB size as ViewportFrame::Reflow does. r=tn
authorMats Palmgren <matspal@gmail.com>
Wed, 24 Apr 2013 18:17:55 +0200
changeset 140711 a4fc2d70eade2cd8b6b330b3fc83abc4a6338677
parent 140710 684a5ca2efb747fb525ea25b4b6b948cee031396
child 140712 450bbfd4853294add45914ac881139565a94b89e
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn
bugs844178
milestone23.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 844178 - Make RecomputePosition adjust the CB size as ViewportFrame::Reflow does. r=tn
layout/base/nsCSSFrameConstructor.cpp
layout/generic/nsViewportFrame.cpp
layout/generic/nsViewportFrame.h
layout/reftests/bugs/844178-ref.html
layout/reftests/bugs/844178.html
layout/reftests/bugs/reftest.list
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -87,16 +87,17 @@
 #include "FrameLayerBuilder.h"
 #include "nsAutoLayoutPhase.h"
 #include "nsCSSRenderingBorders.h"
 #include "nsRenderingContext.h"
 #include "nsStyleStructInlines.h"
 #include "nsAnimationManager.h"
 #include "nsTransitionManager.h"
 #include "nsSVGIntegrationUtils.h"
+#include "nsViewportFrame.h"
 #include <algorithm>
 
 #ifdef MOZ_XUL
 #include "nsIRootBox.h"
 #include "nsIDOMXULCommandDispatcher.h"
 #include "nsIDOMXULDocument.h"
 #include "nsIXULDocument.h"
 #endif
@@ -12448,17 +12449,17 @@ nsCSSFrameConstructor::RecomputePosition
       position->mHeight.GetUnit() != eStyleUnit_Auto) {
     // For the absolute positioning case, set up a fake HTML reflow state for
     // the frame, and then get the offsets from it.
     nsRefPtr<nsRenderingContext> rc = aFrame->PresContext()->GetPresShell()->
       GetReferenceRenderingContext();
 
     // Construct a bogus parent reflow state so that there's a usable
     // containing block reflow state.
-    nsIFrame *parentFrame = aFrame->GetParent();
+    nsIFrame* parentFrame = aFrame->GetParent();
     nsSize parentSize = parentFrame->GetSize();
 
     nsFrameState savedState = parentFrame->GetStateBits();
     nsHTMLReflowState parentReflowState(aFrame->PresContext(), parentFrame,
                                         rc, parentSize);
     parentFrame->RemoveStateBits(~nsFrameState(0));
     parentFrame->AddStateBits(savedState);
 
@@ -12472,17 +12473,20 @@ nsCSSFrameConstructor::RecomputePosition
 
     parentReflowState.mComputedPadding = parentFrame->GetUsedPadding();
     parentReflowState.mComputedBorderPadding =
       parentFrame->GetUsedBorderAndPadding();
 
     nsSize availSize(parentSize.width, NS_INTRINSICSIZE);
 
     nsSize size = aFrame->GetSize();
-    nsSize cbSize = aFrame->GetContainingBlock()->GetSize();
+    ViewportFrame* viewport = do_QueryFrame(parentFrame);
+    nsSize cbSize = viewport ?
+      viewport->AdjustReflowStateAsContainingBlock(&parentReflowState).Size()
+      : aFrame->GetContainingBlock()->GetSize();
     const nsMargin& parentBorder =
       parentReflowState.mStyleBorder->GetComputedBorder();
     cbSize -= nsSize(parentBorder.LeftRight(), parentBorder.TopBottom());
     nsHTMLReflowState reflowState(aFrame->PresContext(), parentReflowState,
                                   aFrame, availSize, cbSize.width,
                                   cbSize.height);
 
     // If we're solving for 'left' or 'top', then compute it here, in order to
--- a/layout/generic/nsViewportFrame.cpp
+++ b/layout/generic/nsViewportFrame.cpp
@@ -23,16 +23,19 @@ using namespace mozilla;
 
 nsIFrame*
 NS_NewViewportFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) ViewportFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(ViewportFrame)
+NS_QUERYFRAME_HEAD(ViewportFrame)
+  NS_QUERYFRAME_ENTRY(ViewportFrame)
+NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
 
 void
 ViewportFrame::Init(nsIContent*      aContent,
                     nsIFrame*        aParent,
                     nsIFrame*        aPrevInFlow)
 {
   Super::Init(aContent, aParent, aPrevInFlow);
 
@@ -127,36 +130,58 @@ ViewportFrame::GetPrefWidth(nsRenderingC
     result = mFrames.FirstChild()->GetPrefWidth(aRenderingContext);
 
   return result;
 }
 
 nsPoint
 ViewportFrame::AdjustReflowStateForScrollbars(nsHTMLReflowState* aReflowState) const
 {
-  // Calculate how much room is available for fixed frames. That means
-  // determining if the viewport is scrollable and whether the vertical and/or
-  // horizontal scrollbars are visible
-
   // Get our prinicpal child frame and see if we're scrollable
   nsIFrame* kidFrame = mFrames.FirstChild();
-  nsIScrollableFrame *scrollingFrame = do_QueryFrame(kidFrame);
+  nsIScrollableFrame* scrollingFrame = do_QueryFrame(kidFrame);
 
   if (scrollingFrame) {
     nsMargin scrollbars = scrollingFrame->GetActualScrollbarSizes();
     aReflowState->SetComputedWidth(aReflowState->ComputedWidth() -
                                    scrollbars.LeftRight());
     aReflowState->availableWidth -= scrollbars.LeftRight();
     aReflowState->SetComputedHeightWithoutResettingResizeFlags(
       aReflowState->ComputedHeight() - scrollbars.TopBottom());
     return nsPoint(scrollbars.left, scrollbars.top);
   }
   return nsPoint(0, 0);
 }
 
+nsRect
+ViewportFrame::AdjustReflowStateAsContainingBlock(nsHTMLReflowState* aReflowState) const
+{
+#ifdef DEBUG
+  nsPoint offset =
+#endif
+    AdjustReflowStateForScrollbars(aReflowState);
+
+  NS_ASSERTION(GetAbsoluteContainingBlock()->GetChildList().IsEmpty() ||
+               (offset.x == 0 && offset.y == 0),
+               "We don't handle correct positioning of fixed frames with "
+               "scrollbars in odd positions");
+
+  // If a scroll position clamping scroll-port size has been set, layout
+  // fixed position elements to this size instead of the computed size.
+  nsRect rect(0, 0, aReflowState->ComputedWidth(), aReflowState->ComputedHeight());
+  nsIPresShell* ps = PresContext()->PresShell();
+  if (ps->IsScrollPositionClampingScrollPortSizeSet()) {
+    rect.SizeTo(ps->GetScrollPositionClampingScrollPortSize());
+  }
+
+  // Make sure content document fixed-position margins are respected.
+  rect.Deflate(ps->GetContentDocumentFixedPositionMargins());
+  return rect;
+}
+
 NS_IMETHODIMP
 ViewportFrame::Reflow(nsPresContext*           aPresContext,
                       nsHTMLReflowMetrics&     aDesiredSize,
                       const nsHTMLReflowState& aReflowState,
                       nsReflowStatus&          aStatus)
 {
   DO_GLOBAL_REFLOW_COUNT("ViewportFrame");
   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
@@ -233,38 +258,17 @@ ViewportFrame::Reflow(nsPresContext*    
       // Set the available height and mComputedHeight to our chosen height.
       reflowState.availableHeight = aDesiredSize.height;
       // Not having border/padding simplifies things
       NS_ASSERTION(reflowState.mComputedBorderPadding == nsMargin(0,0,0,0),
                    "Viewports can't have border/padding");
       reflowState.SetComputedHeight(aDesiredSize.height);
     }
 
-#ifdef DEBUG
-    nsPoint offset =
-#endif
-      AdjustReflowStateForScrollbars(&reflowState);
-
-    NS_ASSERTION(GetAbsoluteContainingBlock()->GetChildList().IsEmpty() ||
-                 (offset.x == 0 && offset.y == 0),
-                 "We don't handle correct positioning of fixed frames with "
-                 "scrollbars in odd positions");
-
-    // If a scroll position clamping scroll-port size has been set, layout
-    // fixed position elements to this size instead of the computed size.
-    nsRect rect(0, 0, reflowState.ComputedWidth(), reflowState.ComputedHeight());
-    if (aPresContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) {
-      nsSize size = aPresContext->PresShell()->
-        GetScrollPositionClampingScrollPortSize();
-      rect.width = size.width;
-      rect.height = size.height;
-    }
-
-    // Make sure content document fixed-position margins are respected.
-    rect.Deflate(aPresContext->PresShell()->GetContentDocumentFixedPositionMargins());
+    nsRect rect = AdjustReflowStateAsContainingBlock(&reflowState);
 
     // Just reflow all the fixed-pos frames.
     rv = GetAbsoluteContainingBlock()->Reflow(this, aPresContext, reflowState, aStatus,
                                               rect,
                                               false, true, true, // XXX could be optimized
                                               &aDesiredSize.mOverflowAreas);
   }
 
--- a/layout/generic/nsViewportFrame.h
+++ b/layout/generic/nsViewportFrame.h
@@ -19,16 +19,18 @@ class nsPresContext;
 
 /**
   * ViewportFrame is the parent of a single child - the doc root frame or a scroll frame 
   * containing the doc root frame. ViewportFrame stores this child in its primary child 
   * list.
   */
 class ViewportFrame : public nsContainerFrame {
 public:
+  NS_DECL_QUERYFRAME_TARGET(ViewportFrame)
+  NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
   typedef nsContainerFrame Super;
 
   ViewportFrame(nsStyleContext* aContext)
     : nsContainerFrame(aContext)
   {}
   virtual ~ViewportFrame() { } // useful for debugging
@@ -63,21 +65,36 @@ public:
 
   /**
    * Get the "type" of the frame
    *
    * @see nsGkAtoms::viewportFrame
    */
   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
 
+  /**
+   * Adjust aReflowState to account for scrollbars and pres shell
+   * GetScrollPositionClampingScrollPortSizeSet and
+   * GetContentDocumentFixedPositionMargins adjustments.
+   * @return the rect to use as containing block rect
+   */
+  nsRect AdjustReflowStateAsContainingBlock(nsHTMLReflowState* aReflowState) const;
+
 #ifdef DEBUG
   NS_IMETHOD GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
 
 private:
   virtual mozilla::layout::FrameChildListID GetAbsoluteListID() const { return kFixedList; }
 
 protected:
+  /**
+   * Calculate how much room is available for fixed frames. That means
+   * determining if the viewport is scrollable and whether the vertical and/or
+   * horizontal scrollbars are visible.  Adjust the computed width/height and
+   * available width for aReflowState accordingly.
+   * @return the current scroll position, or 0,0 if not scrollable
+   */
   nsPoint AdjustReflowStateForScrollbars(nsHTMLReflowState* aReflowState) const;
 };
 
 
 #endif // nsViewportFrame_h___
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/844178-ref.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html><head>
+    <meta charset="utf-8">
+    <title>Testcase for bug 844178</title>
+    <style type="text/css">
+
+        html,body {
+            color:black; background-color:white; font-size:16px; padding:0; margin:0;
+        }
+	
+body {
+  position: fixed;
+  right: 5px;
+  top: 100px;
+  width: 100px;
+  height: 10px;
+  margin:0;
+  padding:0;
+}
+
+:root { overflow:scroll; }
+
+span {
+    background:lime;
+    display:inline-block;
+    width:100px;
+}
+
+</style>
+</head>
+<body><span>Hello</span></body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/844178.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait"><head>
+    <meta charset="utf-8">
+    <title>Testcase for bug 844178</title>
+    <style type="text/css">
+
+        html,body {
+            color:black; background-color:white; font-size:16px; padding:0; margin:0;
+        }
+	
+body {
+  position: fixed;
+  right: 0px;
+  top: 100px;
+  width: 100px;
+  height: 10px;
+  margin:0;
+  padding:0;
+}
+
+:root { overflow:scroll; }
+
+span {
+    background:lime;
+    display:inline-block;
+    width:100px;
+}
+
+</style>
+<script>
+function doTest() {
+  document.body.style.right='5px';
+  document.body.offsetHeight;
+  document.documentElement.removeAttribute('class');
+}
+document.addEventListener("MozReftestInvalidate", doTest, false);
+</script>
+</head>
+<body><span>Hello</span></body>
+</html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1744,15 +1744,16 @@ skip-if(B2G) == 814952-1.html 814952-1-r
 == 817019-1.html about:blank
 skip-if(B2G) == 818276-1.html 818276-1-ref.html
 == 825999.html 825999-ref.html
 == 827577-1a.html 827577-1-ref.html
 == 827577-1b.html 827577-1-ref.html
 == 827799-1.html about:blank
 == 836844-1.html 836844-1-ref.html
 == 841192-1.html 841192-1-ref.html
+== 844178.html 844178-ref.html
 == 846144-1.html 846144-1-ref.html
 == 847850-1.html 847850-1-ref.html
 == 848421-1.html 848421-1-ref.html
 test-pref(layout.css.flexbox.enabled,true) == 849407-1.html 849407-1-ref.html
 == 849996-1.html 849996-1-ref.html
 == 858803-1.html 858803-1-ref.html
 != 860370.html 860370-notref.html