StickyPositionContraints should not need to change to account for a RenderLayer's
authorbdakin@apple.com <bdakin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 22 Jul 2013 21:32:39 +0000 (21:32 +0000)
committerbdakin@apple.com <bdakin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 22 Jul 2013 21:32:39 +0000 (21:32 +0000)
scrollOffset
https://bugs.webkit.org/show_bug.cgi?id=118958
-and corresponding-
<rdar://problem/12469203>

Reviewed by Simon Fraser.

Source/WebCore:

Before this patch, to get sticky offsets right in overflow areas, the
StickyPositionConstraints changed on every scroll to factor it in. This will be a
problem once we can scroll overflow areas on the scrolling thread. The constraints
should never have to change to account for the scroll position. This patch fixes
that issue by changing the StickyPositionViewportConstraints’s containerBlockRect
and stickyBoxRect to be in a coordinate space that is relative to the scrolling
ancestor rather than being absolute. This patch also removes ‘absolute’ from those
variable names since they are no longer absolute.

A few re-names in the StickyPositionViewportConstraints class. The parameter to
computeStickyOffset() used to be called viewportRect, and is now called
constrainingRect. m_absoluteStickyBoxRect is now m_stickyBoxRect, and
m_absoluteContainingBlockRect is now m_containingBlockRect. And finally,
layerPositionForViewportRect() is now layerPositionForConstrainingRect()
* page/scrolling/ScrollingConstraints.cpp:
(WebCore::StickyPositionViewportConstraints::computeStickyOffset):
(WebCore::StickyPositionViewportConstraints::layerPositionForConstrainingRect):
* page/scrolling/ScrollingConstraints.h:
(WebCore::StickyPositionViewportConstraints::StickyPositionViewportConstraints):
(WebCore::StickyPositionViewportConstraints::containingBlockRect):
(WebCore::StickyPositionViewportConstraints::setContainingBlockRect):
(WebCore::StickyPositionViewportConstraints::stickyBoxRect):
(WebCore::StickyPositionViewportConstraints::setStickyBoxRect):
(WebCore::StickyPositionViewportConstraints::operator==):

Accounting for the re-names.
* page/scrolling/ScrollingStateStickyNode.cpp:
(WebCore::ScrollingStateStickyNode::syncLayerPositionForViewportRect):
(WebCore::ScrollingStateStickyNode::dumpProperties):
* page/scrolling/mac/ScrollingTreeStickyNode.mm:
(WebCore::ScrollingTreeStickyNode::parentScrollPositionDidChange):

Compute all values relative to the scrolling ancestor. This requires some juggling
in the overflow case to factor border and padding in or out.
* rendering/RenderBoxModelObject.cpp:
(WebCore::RenderBoxModelObject::computeStickyPositionConstraints):

This is where the scrollOffset should be factored in.
(WebCore::RenderBoxModelObject::stickyPositionOffset):

LayoutTests:

This tests stick in overflow areas where the sticky’s containing block overflows
the overflow area. The sticky object should not extend beyond the overflow area in
that case.

* fast/css/sticky/sticky-top-overflow-container-overflow-expected.html: Added.
* fast/css/sticky/sticky-top-overflow-container-overflow.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@152998 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/css/sticky/sticky-top-overflow-container-overflow-expected.html [new file with mode: 0644]
LayoutTests/fast/css/sticky/sticky-top-overflow-container-overflow.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/page/scrolling/ScrollingConstraints.cpp
Source/WebCore/page/scrolling/ScrollingConstraints.h
Source/WebCore/page/scrolling/ScrollingStateStickyNode.cpp
Source/WebCore/page/scrolling/mac/ScrollingTreeStickyNode.mm
Source/WebCore/rendering/RenderBoxModelObject.cpp

index 8a19b4d..5272c1a 100644 (file)
@@ -1,3 +1,20 @@
+2013-07-22  Beth Dakin  <bdakin@apple.com>
+
+        StickyPositionContraints should not need to change to account for a RenderLayer's 
+        scrollOffset
+        https://bugs.webkit.org/show_bug.cgi?id=118958
+        -and corresponding-
+        <rdar://problem/12469203>
+
+        Reviewed by Simon Fraser.
+
+        This tests stick in overflow areas where the sticky’s containing block overflows 
+        the overflow area. The sticky object should not extend beyond the overflow area in 
+        that case. 
+
+        * fast/css/sticky/sticky-top-overflow-container-overflow-expected.html: Added.
+        * fast/css/sticky/sticky-top-overflow-container-overflow.html: Added.
+
 2013-07-22  Joone Hur  <joone.hur@intel.com>
 
         Rebaseline the caret color test for the Mac port after r152612
diff --git a/LayoutTests/fast/css/sticky/sticky-top-overflow-container-overflow-expected.html b/LayoutTests/fast/css/sticky/sticky-top-overflow-container-overflow-expected.html
new file mode 100644 (file)
index 0000000..b2846df
--- /dev/null
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 150px;
+        height: 500px;
+    }
+    
+    #overflow {
+        width: 600px;
+        height: 550px;
+        overflow: hidden;
+        border: 1px solid black;
+    }
+    
+    .spacer {
+        float: left;
+        width: 10px;
+        height: 1200px;
+    }
+    .container {
+        width: 100px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 100px;
+        height: 200px;
+    }
+
+    .sticky {
+        position: relative;
+        top: 100px;
+        background-color: green;
+    }
+</style>
+</head>
+<body>
+    <div id="overflow">
+        <div class="spacer"></div>
+
+        <div class="group" style="top: -120px">
+            <div class="container">
+                <div class="sticky box" style="top: 200px"></div>
+            </div>
+        </div>
+
+        <div class="group" style="top: -20px">
+            <div class="container">
+                <div class="sticky box" style="top: 120px"></div>
+            </div>
+        </div>
+
+        <div class="group" style="top: 120px">
+            <div class="container">
+                <div class="sticky box" style="top: 0"></div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/LayoutTests/fast/css/sticky/sticky-top-overflow-container-overflow.html b/LayoutTests/fast/css/sticky/sticky-top-overflow-container-overflow.html
new file mode 100644 (file)
index 0000000..c70ca29
--- /dev/null
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 150px;
+        height: 500px;
+    }
+    
+    #overflow {
+        width: 600px;
+        height: 550px;
+        overflow: hidden; /* Still scrollable with JS */
+        border: 1px solid black;
+    }
+    
+    .spacer {
+        float: left;
+        width: 10px;
+        height: 1200px;
+    }
+    .container {
+        width: 100px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 100px;
+        height: 200px;
+    }
+
+    .sticky {
+        position: -webkit-sticky;
+        top: 100px;
+        background-color: green;
+    }
+    
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+
+    .big {
+        width: 50px;
+        height: 300px;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        document.getElementById('overflow').scrollTop = 120;
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div id="overflow">
+        <div class="spacer"></div>
+        <div class="group">
+            <div class="indicator box" style="top: 200px;"></div>
+            <div class="container">
+                <div class="sticky box"></div>
+                <div class="big"></div>
+            </div>
+        </div>
+
+        <div class="group" style="top: 100px">
+            <div class="indicator box" style="top: 120px;"></div>
+            <div class="container">
+                <div class="sticky box"></div>
+                <div class="big"></div>
+            </div>
+        </div>
+
+        <div class="group" style="top: 240px">
+            <div class="indicator box" style="top: 0;"></div>
+            <div class="container">
+                <div class="sticky box"></div>
+                <div class="big"></div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>
index d9c01b7..f72126a 100644 (file)
@@ -1,3 +1,53 @@
+2013-07-22  Beth Dakin  <bdakin@apple.com>
+
+        StickyPositionContraints should not need to change to account for a RenderLayer's 
+        scrollOffset
+        https://bugs.webkit.org/show_bug.cgi?id=118958
+        -and corresponding-
+        <rdar://problem/12469203>
+
+        Reviewed by Simon Fraser.
+
+        Before this patch, to get sticky offsets right in overflow areas, the 
+        StickyPositionConstraints changed on every scroll to factor it in. This will be a 
+        problem once we can scroll overflow areas on the scrolling thread. The constraints 
+        should never have to change to account for the scroll position. This patch fixes 
+        that issue by changing the StickyPositionViewportConstraints’s containerBlockRect 
+        and stickyBoxRect to be in a coordinate space that is relative to the scrolling 
+        ancestor rather than being absolute. This patch also removes ‘absolute’ from those 
+        variable names since they are no longer absolute.
+
+        A few re-names in the StickyPositionViewportConstraints class. The parameter to 
+        computeStickyOffset() used to be called viewportRect, and is now called 
+        constrainingRect. m_absoluteStickyBoxRect is now m_stickyBoxRect, and 
+        m_absoluteContainingBlockRect is now m_containingBlockRect. And finally, 
+        layerPositionForViewportRect() is now layerPositionForConstrainingRect()
+        * page/scrolling/ScrollingConstraints.cpp:
+        (WebCore::StickyPositionViewportConstraints::computeStickyOffset):
+        (WebCore::StickyPositionViewportConstraints::layerPositionForConstrainingRect):
+        * page/scrolling/ScrollingConstraints.h:
+        (WebCore::StickyPositionViewportConstraints::StickyPositionViewportConstraints):
+        (WebCore::StickyPositionViewportConstraints::containingBlockRect):
+        (WebCore::StickyPositionViewportConstraints::setContainingBlockRect):
+        (WebCore::StickyPositionViewportConstraints::stickyBoxRect):
+        (WebCore::StickyPositionViewportConstraints::setStickyBoxRect):
+        (WebCore::StickyPositionViewportConstraints::operator==):
+
+        Accounting for the re-names. 
+        * page/scrolling/ScrollingStateStickyNode.cpp:
+        (WebCore::ScrollingStateStickyNode::syncLayerPositionForViewportRect):
+        (WebCore::ScrollingStateStickyNode::dumpProperties):
+        * page/scrolling/mac/ScrollingTreeStickyNode.mm:
+        (WebCore::ScrollingTreeStickyNode::parentScrollPositionDidChange):
+
+        Compute all values relative to the scrolling ancestor. This requires some juggling 
+        in the overflow case to factor border and padding in or out.
+        * rendering/RenderBoxModelObject.cpp:
+        (WebCore::RenderBoxModelObject::computeStickyPositionConstraints):
+
+        This is where the scrollOffset should be factored in.
+        (WebCore::RenderBoxModelObject::stickyPositionOffset):
+
 2013-07-22  Dean Jackson  <dino@apple.com>
 
         PlugIn content can disappear after restarting
index 0bbc657..4b3f4d6 100644 (file)
@@ -45,14 +45,14 @@ FloatPoint FixedPositionViewportConstraints::layerPositionForViewportRect(const
     return m_layerPositionAtLastLayout + offset;
 }
 
-FloatSize StickyPositionViewportConstraints::computeStickyOffset(const FloatRect& viewportRect) const
+FloatSize StickyPositionViewportConstraints::computeStickyOffset(const FloatRect& constrainingRect) const
 {
-    FloatRect boxRect = m_absoluteStickyBoxRect;
+    FloatRect boxRect = m_stickyBoxRect;
     
     if (hasAnchorEdge(AnchorEdgeRight)) {
-        float rightLimit = viewportRect.maxX() - m_rightOffset;
-        float rightDelta = std::min<float>(0, rightLimit - m_absoluteStickyBoxRect.maxX());
-        float availableSpace = std::min<float>(0, m_absoluteContainingBlockRect.x() - m_absoluteStickyBoxRect.x());
+        float rightLimit = constrainingRect.maxX() - m_rightOffset;
+        float rightDelta = std::min<float>(0, rightLimit - m_stickyBoxRect.maxX());
+        float availableSpace = std::min<float>(0, m_containingBlockRect.x() - m_stickyBoxRect.x());
         if (rightDelta < availableSpace)
             rightDelta = availableSpace;
 
@@ -60,9 +60,9 @@ FloatSize StickyPositionViewportConstraints::computeStickyOffset(const FloatRect
     }
 
     if (hasAnchorEdge(AnchorEdgeLeft)) {
-        float leftLimit = viewportRect.x() + m_leftOffset;
-        float leftDelta = std::max<float>(0, leftLimit - m_absoluteStickyBoxRect.x());
-        float availableSpace = std::max<float>(0, m_absoluteContainingBlockRect.maxX() - m_absoluteStickyBoxRect.maxX());
+        float leftLimit = constrainingRect.x() + m_leftOffset;
+        float leftDelta = std::max<float>(0, leftLimit - m_stickyBoxRect.x());
+        float availableSpace = std::max<float>(0, m_containingBlockRect.maxX() - m_stickyBoxRect.maxX());
         if (leftDelta > availableSpace)
             leftDelta = availableSpace;
 
@@ -70,9 +70,9 @@ FloatSize StickyPositionViewportConstraints::computeStickyOffset(const FloatRect
     }
     
     if (hasAnchorEdge(AnchorEdgeBottom)) {
-        float bottomLimit = viewportRect.maxY() - m_bottomOffset;
-        float bottomDelta = std::min<float>(0, bottomLimit - m_absoluteStickyBoxRect.maxY());
-        float availableSpace = std::min<float>(0, m_absoluteContainingBlockRect.y() - m_absoluteStickyBoxRect.y());
+        float bottomLimit = constrainingRect.maxY() - m_bottomOffset;
+        float bottomDelta = std::min<float>(0, bottomLimit - m_stickyBoxRect.maxY());
+        float availableSpace = std::min<float>(0, m_containingBlockRect.y() - m_stickyBoxRect.y());
         if (bottomDelta < availableSpace)
             bottomDelta = availableSpace;
 
@@ -80,21 +80,21 @@ FloatSize StickyPositionViewportConstraints::computeStickyOffset(const FloatRect
     }
 
     if (hasAnchorEdge(AnchorEdgeTop)) {
-        float topLimit = viewportRect.y() + m_topOffset;
-        float topDelta = std::max<float>(0, topLimit - m_absoluteStickyBoxRect.y());
-        float availableSpace = std::max<float>(0, m_absoluteContainingBlockRect.maxY() - m_absoluteStickyBoxRect.maxY());
+        float topLimit = constrainingRect.y() + m_topOffset;
+        float topDelta = std::max<float>(0, topLimit - m_stickyBoxRect.y());
+        float availableSpace = std::max<float>(0, m_containingBlockRect.maxY() - m_stickyBoxRect.maxY());
         if (topDelta > availableSpace)
             topDelta = availableSpace;
 
         boxRect.move(0, topDelta);
     }
 
-    return boxRect.location() - m_absoluteStickyBoxRect.location();
+    return boxRect.location() - m_stickyBoxRect.location();
 }
 
-FloatPoint StickyPositionViewportConstraints::layerPositionForViewportRect(const FloatRect& viewportRect) const
+FloatPoint StickyPositionViewportConstraints::layerPositionForConstrainingRect(const FloatRect& constrainingRect) const
 {
-    FloatSize offset = computeStickyOffset(viewportRect);
+    FloatSize offset = computeStickyOffset(constrainingRect);
     return m_layerPositionAtLastLayout + offset - m_stickyOffsetAtLastLayout;
 }
 
index f84a108..9eff144 100644 (file)
@@ -125,18 +125,18 @@ public:
         , m_rightOffset(other.m_rightOffset)
         , m_topOffset(other.m_topOffset)
         , m_bottomOffset(other.m_bottomOffset)
-        , m_absoluteContainingBlockRect(other.m_absoluteContainingBlockRect)
-        , m_absoluteStickyBoxRect(other.m_absoluteStickyBoxRect)
+        , m_containingBlockRect(other.m_containingBlockRect)
+        , m_stickyBoxRect(other.m_stickyBoxRect)
         , m_stickyOffsetAtLastLayout(other.m_stickyOffsetAtLastLayout)
         , m_layerPositionAtLastLayout(other.m_layerPositionAtLastLayout)
     { }
 
-    FloatSize computeStickyOffset(const FloatRect& viewportRect) const;
+    FloatSize computeStickyOffset(const FloatRect& constrainingRect) const;
 
     const FloatSize stickyOffsetAtLastLayout() const { return m_stickyOffsetAtLastLayout; }
     void setStickyOffsetAtLastLayout(const FloatSize& offset) { m_stickyOffsetAtLastLayout = offset; }
 
-    FloatPoint layerPositionForViewportRect(const FloatRect& viewportRect) const;
+    FloatPoint layerPositionForConstrainingRect(const FloatRect& constrainingRect) const;
 
     const FloatPoint& layerPositionAtLastLayout() const { return m_layerPositionAtLastLayout; }
     void setLayerPositionAtLastLayout(const FloatPoint& point) { m_layerPositionAtLastLayout = point; }
@@ -151,11 +151,13 @@ public:
     void setTopOffset(float offset) { m_topOffset = offset; }
     void setBottomOffset(float offset) { m_bottomOffset = offset; }
 
-    FloatRect absoluteContainingBlockRect() const { return m_absoluteContainingBlockRect; }
-    void setAbsoluteContainingBlockRect(const FloatRect& rect) { m_absoluteContainingBlockRect = rect; }
+    // containingBlockRect() is in the scrolling ancestor's coordinate space.
+    FloatRect containingBlockRect() const { return m_containingBlockRect; }
+    void setContainingBlockRect(const FloatRect& rect) { m_containingBlockRect = rect; }
 
-    FloatRect absoluteStickyBoxRect() const { return m_absoluteStickyBoxRect; }
-    void setAbsoluteStickyBoxRect(const FloatRect& rect) { m_absoluteStickyBoxRect = rect; }
+    // stickyBoxRect() is in the scrolling ancestor's coordinate space.
+    FloatRect stickyBoxRect() const { return m_stickyBoxRect; }
+    void setStickyBoxRect(const FloatRect& rect) { m_stickyBoxRect = rect; }
 
     bool operator==(const StickyPositionViewportConstraints& other) const
     {
@@ -163,8 +165,8 @@ public:
             && m_rightOffset == other.m_rightOffset
             && m_topOffset == other.m_topOffset
             && m_bottomOffset == other.m_bottomOffset
-            && m_absoluteContainingBlockRect == other.m_absoluteContainingBlockRect
-            && m_absoluteStickyBoxRect == other.m_absoluteStickyBoxRect
+            && m_containingBlockRect == other.m_containingBlockRect
+            && m_stickyBoxRect == other.m_stickyBoxRect
             && m_stickyOffsetAtLastLayout == other.m_stickyOffsetAtLastLayout
             && m_layerPositionAtLastLayout == other.m_layerPositionAtLastLayout;
     }
@@ -178,8 +180,8 @@ private:
     float m_rightOffset;
     float m_topOffset;
     float m_bottomOffset;
-    FloatRect m_absoluteContainingBlockRect;
-    FloatRect m_absoluteStickyBoxRect;
+    FloatRect m_containingBlockRect;
+    FloatRect m_stickyBoxRect;
     FloatSize m_stickyOffsetAtLastLayout;
     FloatPoint m_layerPositionAtLastLayout;
 };
index 4831e51..73b5ade 100644 (file)
@@ -72,7 +72,7 @@ void ScrollingStateStickyNode::updateConstraints(const StickyPositionViewportCon
 
 void ScrollingStateStickyNode::syncLayerPositionForViewportRect(const LayoutRect& viewportRect)
 {
-    FloatPoint position = m_constraints.layerPositionForViewportRect(viewportRect);
+    FloatPoint position = m_constraints.layerPositionForConstrainingRect(viewportRect);
     graphicsLayer()->syncPosition(position);
 }
 
@@ -112,15 +112,15 @@ void ScrollingStateStickyNode::dumpProperties(TextStream& ts, int indent) const
     }
 
     writeIndent(ts, indent + 1);
-    FloatRect r = m_constraints.absoluteContainingBlockRect();
+    FloatRect r = m_constraints.containingBlockRect();
     ts << "(containing block rect " << r.x() << ", " << r.y() << " " << r.width() << " x " << r.height() << ")\n";
 
     writeIndent(ts, indent + 1);
-    r = m_constraints.absoluteStickyBoxRect();
+    r = m_constraints.stickyBoxRect();
     ts << "(sticky box rect " << r.x() << " " << r.y() << " " << r.width() << " " << r.height() << ")\n";
 
     writeIndent(ts, indent + 1);
-    r = m_constraints.absoluteStickyBoxRect();
+    r = m_constraints.stickyBoxRect();
     ts << "(sticky box rect " << r.x() << " " << r.y() << " " << r.width() << " " << r.height() << ")\n";
 
     writeIndent(ts, indent + 1);
index 9678ec8..20f8474 100644 (file)
@@ -65,10 +65,10 @@ static inline CGPoint operator*(CGPoint& a, const CGSize& b)
 
 void ScrollingTreeStickyNode::parentScrollPositionDidChange(const IntRect& viewportRect, const FloatSize& cumulativeDelta)
 {
-    FloatPoint layerPosition = m_constraints.layerPositionForViewportRect(viewportRect);
+    FloatPoint layerPosition = m_constraints.layerPositionForConstrainingRect(viewportRect);
 
     // FIXME: Subtracting the cumulativeDelta is not totally sufficient to get the new position right for nested
-    // sticky objects. We probably need a way to modify the absoluteContainingBlockRect in the ViewportContraints
+    // sticky objects. We probably need a way to modify the containingBlockRect in the ViewportContraints
     // to get this right in all cases.
     layerPosition -= cumulativeDelta;
 
index 593a500..730ab0f 100644 (file)
@@ -527,8 +527,19 @@ LayoutPoint RenderBoxModelObject::adjustedPositionRelativeToOffsetParent(const L
 void RenderBoxModelObject::computeStickyPositionConstraints(StickyPositionViewportConstraints& constraints, const FloatRect& constrainingRect) const
 {
     RenderBlock* containingBlock = this->containingBlock();
+    RenderLayer* enclosingClippingLayer = layer()->enclosingOverflowClipLayer(ExcludeSelf);
+    RenderBox* enclosingClippingBox = enclosingClippingLayer ? toRenderBox(enclosingClippingLayer->renderer()) : view();
+
+    LayoutRect containerContentRect;
+    if (!enclosingClippingLayer || (containingBlock != enclosingClippingBox))
+        containerContentRect = containingBlock->contentBoxRect();
+    else {
+        containerContentRect = containingBlock->layoutOverflowRect();
+        LayoutPoint containerLocation = containerContentRect.location() + LayoutPoint(containingBlock->borderLeft() + containingBlock->paddingLeft(),
+            containingBlock->borderTop() + containingBlock->paddingTop());
+        containerContentRect.setLocation(containerLocation);
+    }
 
-    LayoutRect containerContentRect = containingBlock->contentBoxRect();
     LayoutUnit maxWidth = containingBlock->availableLogicalWidth();
 
     // Sticky positioned element ignore any override logical width on the containing block (as they don't call
@@ -540,26 +551,37 @@ void RenderBoxModelObject::computeStickyPositionConstraints(StickyPositionViewpo
 
     // Compute the container-relative area within which the sticky element is allowed to move.
     containerContentRect.contract(minMargin);
-    // Map to the view to avoid including page scale factor.
-    constraints.setAbsoluteContainingBlockRect(containingBlock->localToContainerQuad(FloatRect(containerContentRect), view()).boundingBox());
 
+    // Finally compute container rect relative to the scrolling ancestor.
+    FloatRect containerRectRelativeToScrollingAncestor = containingBlock->localToContainerQuad(FloatRect(containerContentRect), enclosingClippingBox).boundingBox();
+    if (enclosingClippingLayer) {
+        FloatPoint containerLocationRelativeToScrollingAncestor = containerRectRelativeToScrollingAncestor.location() -
+            FloatSize(enclosingClippingBox->borderLeft() + enclosingClippingBox->paddingLeft(),
+            enclosingClippingBox->borderTop() + enclosingClippingBox->paddingTop());
+        if (enclosingClippingBox != containingBlock)
+            containerLocationRelativeToScrollingAncestor += enclosingClippingLayer->scrollOffset();
+        containerRectRelativeToScrollingAncestor.setLocation(containerLocationRelativeToScrollingAncestor);
+    }
+    constraints.setContainingBlockRect(containerRectRelativeToScrollingAncestor);
+
+    // Now compute the sticky box rect, also relative to the scrolling ancestor.
     LayoutRect stickyBoxRect = frameRectForStickyPositioning();
     LayoutRect flippedStickyBoxRect = stickyBoxRect;
     containingBlock->flipForWritingMode(flippedStickyBoxRect);
-    LayoutPoint stickyLocation = flippedStickyBoxRect.location();
+    FloatRect stickyBoxRelativeToScrollingAnecstor = flippedStickyBoxRect;
 
-    // FIXME: sucks to call localToAbsolute again, but we can't just offset from the previously computed rect if there are transforms.
+    // FIXME: sucks to call localToContainerQuad again, but we can't just offset from the previously computed rect if there are transforms.
     // Map to the view to avoid including page scale factor.
-    FloatRect absContainerFrame = containingBlock->localToContainerQuad(FloatRect(FloatPoint(), containingBlock->size()), view()).boundingBox();
-
-    if (containingBlock->hasOverflowClip()) {
-        IntSize scrollOffset = containingBlock->layer()->scrollOffset();
-        stickyLocation -= scrollOffset;
+    FloatPoint stickyLocationRelativeToScrollingAncestor = flippedStickyBoxRect.location() + containingBlock->localToContainerQuad(FloatRect(FloatPoint(), containingBlock->size()), enclosingClippingBox).boundingBox().location();
+    if (enclosingClippingLayer) {
+        stickyLocationRelativeToScrollingAncestor -= FloatSize(enclosingClippingBox->borderLeft() + enclosingClippingBox->paddingLeft(),
+            enclosingClippingBox->borderTop() + enclosingClippingBox->paddingTop());
+        if (enclosingClippingBox != containingBlock)
+            stickyLocationRelativeToScrollingAncestor += enclosingClippingLayer->scrollOffset();
     }
-
-    // We can't call localToAbsolute on |this| because that will recur. FIXME: For now, assume that |this| is not transformed.
-    FloatRect absoluteStickyBoxRect(absContainerFrame.location() + stickyLocation, flippedStickyBoxRect.size());
-    constraints.setAbsoluteStickyBoxRect(absoluteStickyBoxRect);
+    // FIXME: For now, assume that |this| is not transformed.
+    stickyBoxRelativeToScrollingAnecstor.setLocation(stickyLocationRelativeToScrollingAncestor);
+    constraints.setStickyBoxRect(stickyBoxRelativeToScrollingAnecstor);
 
     if (!style()->left().isAuto()) {
         constraints.setLeftOffset(valueForLength(style()->left(), constrainingRect.width(), view()));
@@ -592,6 +614,9 @@ LayoutSize RenderBoxModelObject::stickyPositionOffset() const
         RenderBox* enclosingClippingBox = toRenderBox(enclosingClippingLayer->renderer());
         LayoutRect clipRect = enclosingClippingBox->overflowClipRect(LayoutPoint(), 0); // FIXME: make this work in regions.
         constrainingRect = enclosingClippingBox->localToContainerQuad(FloatRect(clipRect), view()).boundingBox();
+
+        FloatPoint scrollOffset = FloatPoint() + enclosingClippingLayer->scrollOffset();
+        constrainingRect.setLocation(scrollOffset);
     } else {
         LayoutRect viewportRect = view()->frameView()->viewportConstrainedVisibleContentRect();
         float scale = 1;