REGRESSION (r242132): Nested position:sticky elements move incorrectly
[WebKit-https.git] / Source / WebCore / page / scrolling / cocoa / ScrollingTreeStickyNode.mm
1 /*
2  * Copyright (C) 2012 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "ScrollingTreeStickyNode.h"
28
29 #if ENABLE(ASYNC_SCROLLING)
30
31 #import "Logging.h"
32 #import "ScrollingStateStickyNode.h"
33 #import "ScrollingTree.h"
34 #import "ScrollingTreeFrameScrollingNode.h"
35 #import "ScrollingTreeOverflowScrollingNode.h"
36 #import "WebCoreCALayerExtras.h"
37 #import <wtf/text/TextStream.h>
38
39 namespace WebCore {
40
41 Ref<ScrollingTreeStickyNode> ScrollingTreeStickyNode::create(ScrollingTree& scrollingTree, ScrollingNodeID nodeID)
42 {
43     return adoptRef(*new ScrollingTreeStickyNode(scrollingTree, nodeID));
44 }
45
46 ScrollingTreeStickyNode::ScrollingTreeStickyNode(ScrollingTree& scrollingTree, ScrollingNodeID nodeID)
47     : ScrollingTreeNode(scrollingTree, ScrollingNodeType::Sticky, nodeID)
48 {
49     scrollingTree.fixedOrStickyNodeAdded();
50 }
51
52 ScrollingTreeStickyNode::~ScrollingTreeStickyNode()
53 {
54     scrollingTree().fixedOrStickyNodeRemoved();
55 }
56
57 void ScrollingTreeStickyNode::commitStateBeforeChildren(const ScrollingStateNode& stateNode)
58 {
59     const ScrollingStateStickyNode& stickyStateNode = downcast<ScrollingStateStickyNode>(stateNode);
60
61     if (stickyStateNode.hasChangedProperty(ScrollingStateNode::Layer))
62         m_layer = stickyStateNode.layer();
63
64     if (stateNode.hasChangedProperty(ScrollingStateStickyNode::ViewportConstraints))
65         m_constraints = stickyStateNode.viewportConstraints();
66 }
67
68 void ScrollingTreeStickyNode::applyLayerPositions(const FloatRect& layoutViewport, FloatSize& cumulativeDelta)
69 {
70     FloatRect constrainingRect;
71
72     auto* enclosingScrollingNode = parent();
73     if (is<ScrollingTreeOverflowScrollingNode>(enclosingScrollingNode))
74         constrainingRect = FloatRect(downcast<ScrollingTreeOverflowScrollingNode>(*enclosingScrollingNode).currentScrollPosition(), m_constraints.constrainingRectAtLastLayout().size());
75     else if (is<ScrollingTreeFrameScrollingNode>(enclosingScrollingNode))
76         constrainingRect = layoutViewport;
77     else
78         return;
79
80     LOG_WITH_STREAM(Scrolling, stream << "ScrollingTreeStickyNode " << scrollingNodeID() << " relatedNodeScrollPositionDidChange: new viewport " << layoutViewport << " constrainingRectAtLastLayout " << m_constraints.constrainingRectAtLastLayout() << " last layer pos " << m_constraints.layerPositionAtLastLayout());
81
82     FloatPoint layerPosition = m_constraints.layerPositionForConstrainingRect(constrainingRect) - m_constraints.alignmentOffset();
83     [m_layer _web_setLayerTopLeftPosition:layerPosition];
84
85     cumulativeDelta += layerPosition - m_constraints.layerPositionAtLastLayout();
86 }
87
88 void ScrollingTreeStickyNode::dumpProperties(TextStream& ts, ScrollingStateTreeAsTextBehavior behavior) const
89 {
90     ts << "sticky node";
91
92     ScrollingTreeNode::dumpProperties(ts, behavior);
93     ts.dumpProperty("sticky constraints", m_constraints);
94
95     if (behavior & ScrollingStateTreeAsTextBehaviorIncludeLayerPositions) {
96         FloatRect layerBounds = [m_layer bounds];
97         FloatPoint anchorPoint = [m_layer anchorPoint];
98         FloatPoint position = [m_layer position];
99         FloatPoint layerTopLeft = position - toFloatSize(anchorPoint) * layerBounds.size() + m_constraints.alignmentOffset();
100         ts.dumpProperty("layer top left", layerTopLeft);
101     }
102 }
103
104 } // namespace WebCore
105
106 #endif // ENABLE(ASYNC_SCROLLING)