Pages with position:fixed elements should still be able to scroll on
the scrolling thread
-and corresponding-
<rdar://problem/
10857315>
Reviewed by Simon Fraser.
Source/WebCore:
This patch adds two new classes. ScrollingStateFixedNode is a class
to represent fixed nodes in the state tree, and
ScrollingTreeFixedNode represents fixed node in the scrolling tree
over on the scrolling thread.
* WebCore.xcodeproj/project.pbxproj:
When we are (non-programatically) scrolling fixed objects on the
scrolling thread, we do not want to do any work here.
* page/FrameView.cpp:
(WebCore::FrameView::updateFixedElementsAfterScrolling):
Whenever we sync the position of the main frame's layer, we have to
do the same for scrolling tree children.
* page/scrolling/ScrollingCoordinator.cpp:
(WebCore::ScrollingCoordinator::updateMainFrameScrollPosition):
New ScrollingNodeType -- FixedNode, yay! And two new functions
specific to dealing with FixedNodes.
* page/scrolling/ScrollingCoordinator.h:
(WebCore::ScrollingCoordinator::updateViewportConstrainedNode):
(WebCore::ScrollingCoordinator::syncChildPositions):
This is the new class that represents fixed nodes in the state tree.
All of the changed properties are stored within
FixedPositionViewportConstraints.
* page/scrolling/ScrollingStateFixedNode.cpp: Added.
(WebCore):
(WebCore::ScrollingStateFixedNode::create):
(WebCore::ScrollingStateFixedNode::ScrollingStateFixedNode):
(WebCore::ScrollingStateFixedNode::~ScrollingStateFixedNode):
(WebCore::ScrollingStateFixedNode::updateConstraints):
(WebCore::ScrollingStateFixedNode::dumpProperties):
* page/scrolling/ScrollingStateFixedNode.h: Added.
(WebCore):
(ScrollingStateFixedNode):
(WebCore::ScrollingStateFixedNode::viewportConstraints):
(WebCore::toScrollingStateFixedNode):
Make sure to create the right type of clone for each node.
* page/scrolling/ScrollingStateNode.cpp:
(WebCore::ScrollingStateNode::cloneAndReset):
Now that m_children may be anything other than null, I found this
bug. We encounter it when the parameter to removeChild is this and we
want to remove all of our children. In that case, this is obviously
not found in its own child array.
(WebCore::ScrollingStateNode::removeChild):
ScrollingStateNode now caches the GraphicsLayer in addition to the
PlatformLayer. This will allow us to sync the GraphicsLayer position
at the appropriate times.
* page/scrolling/ScrollingStateNode.h:
(WebCore::ScrollingStateNode::isScrollingStateFixedNode):
(WebCore::ScrollingStateNode::graphicsLayer):
(ScrollingStateNode):
Handle fixed nodes.
* page/scrolling/ScrollingTree.cpp:
(WebCore::ScrollingTree::updateTreeFromStateNode):
New function parentScrollPositionDidChange() is called on children
when the parent has scrolled.
* page/scrolling/ScrollingTreeNode.h:
(ScrollingTreeNode):
* page/scrolling/ScrollingTreeScrollingNode.h:
(ScrollingTreeScrollingNode):
Return true for supportsFixedPositionLayers().
* page/scrolling/mac/ScrollingCoordinatorMac.h:
(ScrollingCoordinatorMac):
Handle fixed nodes.
* page/scrolling/mac/ScrollingCoordinatorMac.mm:
(WebCore::ScrollingCoordinatorMac::attachToStateTree):
Now that m_children can be non-null I caught this pre-existing bug
where we would come times remove a node without updating the HashMap.
This patch fixes that by consolidating the removal into one function.
(WebCore::ScrollingCoordinatorMac::removeNode):
(WebCore::ScrollingCoordinatorMac::detachFromStateTree):
(WebCore::ScrollingCoordinatorMac::clearStateTree):
Update the GraphicsLayers to reflect the new position that the
Scrolling thread has moved the underlying CALayer to already.
(WebCore::ScrollingCoordinatorMac::syncChildPositions):
Pass new constraints over to the appropriate state node.
(WebCore::ScrollingCoordinatorMac::updateViewportConstrainedNode):
Cache the GraphicsLayer in addition to the PlatformLayer.
* page/scrolling/mac/ScrollingStateNodeMac.mm:
(WebCore::ScrollingStateNode::setScrollLayer):
Here is the new class that represents fixed nodes over on the
scrolling thread.
* page/scrolling/mac/ScrollingTreeFixedNode.h: Added.
(WebCore):
(ScrollingTreeFixedNode):
* page/scrolling/mac/ScrollingTreeFixedNode.mm: Added.
(WebCore):
(WebCore::ScrollingTreeFixedNode::create):
(WebCore::ScrollingTreeFixedNode::ScrollingTreeFixedNode):
(WebCore::ScrollingTreeFixedNode::~ScrollingTreeFixedNode):
(WebCore::ScrollingTreeFixedNode::update):
This is where the magic happens. re-position the fixed object when
its parent has scrolled so that it appears to have not moved at all.
(WebCore::ScrollingTreeFixedNode::parentScrollPositionDidChange):
Whenever we change the position of a scrolling layer, tell our
children.
* page/scrolling/mac/ScrollingTreeScrollingNodeMac.mm:
(WebCore::ScrollingTreeScrollingNodeMac::setScrollLayerPosition):
Handle fixed nodes.
* rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::attachToScrollingCoordinator):
detachFromScrollingCoordinator() needs to be public so that it can be
called from RenderLayerCompositor for fixed nodes.
* rendering/RenderLayerBacking.h:
(RenderLayerBacking):
RenderLayerCompositor takes control of attaching and detaching fixed
nodes to/from the ScrollingCoordinator.
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::flushPendingLayerChanges):
(WebCore::RenderLayerCompositor::didFlushChangesForLayer):
(WebCore::RenderLayerCompositor::updateBacking):
(WebCore::RenderLayerCompositor::layerWillBeRemoved):
(WebCore::RenderLayerCompositor::didMoveOnscreen):
(WebCore::RenderLayerCompositor::willMoveOffscreen):
(WebCore::RenderLayerCompositor::clearBackingForLayerIncludingDescendants):
(WebCore::isRootmostFixedOrStickyLayer):
(WebCore):
(WebCore::RenderLayerCompositor::updateViewportConstraintStatus):
(WebCore::RenderLayerCompositor::addViewportConstrainedLayer):
(WebCore::RenderLayerCompositor::removeViewportConstrainedLayer):
(WebCore::RenderLayerCompositor::computeViewportConstraints):
(WebCore::nearestScrollingCoordinatorAncestor):
(WebCore::RenderLayerCompositor::registerOrUpdateViewportConstrainedLayer):
(WebCore::RenderLayerCompositor::unregisterViewportConstrainedLayer):
(WebCore::RenderLayerCompositor::registerAllViewportConstrainedLayers):
(WebCore::RenderLayerCompositor::unregisterAllViewportConstrainedLayers):
* rendering/RenderLayerCompositor.h:
(WebCore):
(RenderLayerCompositor):
LayoutTests:
New tests.
* platform/mac/tiled-drawing/fixed: Added.
* platform/mac/tiled-drawing/fixed/absolute-inside-fixed-expected.txt: Added.
* platform/mac/tiled-drawing/fixed/absolute-inside-fixed.html: Added.
* platform/mac/tiled-drawing/fixed/fixed-position-out-of-view-expected.txt: Added.
* platform/mac/tiled-drawing/fixed/fixed-position-out-of-view-negative-zindex-expected.txt: Added.
* platform/mac/tiled-drawing/fixed/fixed-position-out-of-view-negative-zindex.html: Added.
* platform/mac/tiled-drawing/fixed/fixed-position-out-of-view.html: Added.
* platform/mac/tiled-drawing/fixed/four-bars-expected.txt: Added.
* platform/mac/tiled-drawing/fixed/four-bars.html: Added.
* platform/mac/tiled-drawing/fixed/nested-fixed-expected.txt: Added.
* platform/mac/tiled-drawing/fixed/nested-fixed.html: Added.
* platform/mac/tiled-drawing/fixed/percentage-inside-fixed-expected.txt: Added.
* platform/mac/tiled-drawing/fixed/percentage-inside-fixed.html: Added.
These two tests are supposed to be in "slow scrolling" mode. Now that
fixed elements can scroll "fast," we need something else to force
slow scrolling. We should probably just add something to
window.internals to do that, but in the meantime,
background-attachment:fixed will work.
* platform/mac/tiled-drawing/scrolling-tree-slow-scrolling-expected.txt:
* platform/mac/tiled-drawing/scrolling-tree-slow-scrolling.html:
* platform/mac/tiled-drawing/tile-coverage-slow-scrolling-expected.txt:
* platform/mac/tiled-drawing/tile-coverage-slow-scrolling.html:
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@133536
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2012-11-05 Beth Dakin <bdakin@apple.com>
+
+ https://bugs.webkit.org/show_bug.cgi?id=101001
+ Pages with position:fixed elements should still be able to scroll on
+ the scrolling thread
+ -and corresponding-
+ <rdar://problem/10857315>
+
+ Reviewed by Simon Fraser.
+
+ New tests.
+ * platform/mac/tiled-drawing/fixed: Added.
+ * platform/mac/tiled-drawing/fixed/absolute-inside-fixed-expected.txt: Added.
+ * platform/mac/tiled-drawing/fixed/absolute-inside-fixed.html: Added.
+ * platform/mac/tiled-drawing/fixed/fixed-position-out-of-view-expected.txt: Added.
+ * platform/mac/tiled-drawing/fixed/fixed-position-out-of-view-negative-zindex-expected.txt: Added.
+ * platform/mac/tiled-drawing/fixed/fixed-position-out-of-view-negative-zindex.html: Added.
+ * platform/mac/tiled-drawing/fixed/fixed-position-out-of-view.html: Added.
+ * platform/mac/tiled-drawing/fixed/four-bars-expected.txt: Added.
+ * platform/mac/tiled-drawing/fixed/four-bars.html: Added.
+ * platform/mac/tiled-drawing/fixed/nested-fixed-expected.txt: Added.
+ * platform/mac/tiled-drawing/fixed/nested-fixed.html: Added.
+ * platform/mac/tiled-drawing/fixed/percentage-inside-fixed-expected.txt: Added.
+ * platform/mac/tiled-drawing/fixed/percentage-inside-fixed.html: Added.
+
+ These two tests are supposed to be in "slow scrolling" mode. Now that
+ fixed elements can scroll "fast," we need something else to force
+ slow scrolling. We should probably just add something to
+ window.internals to do that, but in the meantime,
+ background-attachment:fixed will work.
+ * platform/mac/tiled-drawing/scrolling-tree-slow-scrolling-expected.txt:
+ * platform/mac/tiled-drawing/scrolling-tree-slow-scrolling.html:
+ * platform/mac/tiled-drawing/tile-coverage-slow-scrolling-expected.txt:
+ * platform/mac/tiled-drawing/tile-coverage-slow-scrolling.html:
+
2012-11-05 Alice Boxhall <aboxhall@chromium.org>
Unreviewed gardening. Mark fonts/cursive.html as flaky on MountainLion as well as Lion.
--- /dev/null
+(Scrolling node
+ (viewport rect 0 0 785 600)
+ (contents size 785 2710)
+ (requested scroll position 0 200)
+ (children 1
+ (Fixed node
+ (anchor edges: AnchorEdgeLeft AnchorEdgeTop)
+ (viewport rect at last layout: 0.00 200.00 785.00 600.00)
+ (layer position at last layout 8.00 8.00)
+ )
+ )
+)
+
--- /dev/null
+<!DOCTYPE html>
+<html>
+
+<head>
+ <style>
+ body {
+ margin: 0;
+ height: 2500px;
+ }
+
+ .box {
+ height: 100px;
+ width: 100px;
+ }
+
+ .outer {
+ position: fixed;
+ left: 10px;
+ top: 10px;
+ width: 100px;
+ height: 100px;
+ outline: 2px solid black;
+ }
+
+ .wrapper {
+ position: absolute;
+ background-color: green;
+ }
+
+ .indicator {
+ margin-left: 10px;
+ margin-top: 210px;
+ background-color: red;
+ }
+ </style>
+ <script>
+ if (window.testRunner) {
+ testRunner.waitUntilDone();
+ testRunner.dumpAsText();
+ }
+
+ function doScroll()
+ {
+ window.setTimeout(function() {
+ window.scrollTo(0, 200);
+ if (window.internals) {
+ document.getElementById('results').innerText = internals.scrollingStateTreeAsText(document);
+ testRunner.notifyDone();
+ }
+ }, 10);
+ }
+
+ window.addEventListener('load', doScroll, false);
+ </script>
+</head>
+<body>
+ <!-- The green box should obscure the red box -->
+ <pre id="results"></pre>
+ <div class="indicator box"></div>
+ <div class="outer box">
+ <div class="wrapper box">
+ </div>
+ </div>
+</body>
+</html>
--- /dev/null
+(Scrolling node
+ (viewport rect 0 0 785 600)
+ (contents size 785 2213)
+ (requested scroll position 0 200)
+ (children 1
+ (Fixed node
+ (anchor edges: AnchorEdgeLeft AnchorEdgeTop)
+ (viewport rect at last layout: 0.00 200.00 785.00 600.00)
+ (layer position at last layout 2.00 15.00)
+ )
+ )
+)
+
--- /dev/null
+<!DOCTYPE html>
+<html>
+
+<head>
+ <style type="text/css" media="screen">
+ body {
+ margin: 0;
+ height: 2200px;
+ }
+
+ .scrolly {
+ overflow: scroll;
+ width:200px;
+ height:200px;
+ border: 2px solid black;
+ }
+
+ .big {
+ border:1px solid purple;
+ height: 500px;
+ width:50px;
+ }
+
+ .fixed {
+ height: 100px;
+ width: 100px;
+ position: fixed;
+ background: green;
+ }
+ </style>
+ <script type="text/javascript" charset="utf-8">
+ if (window.testRunner) {
+ testRunner.waitUntilDone();
+ testRunner.dumpAsText();
+ }
+
+ function doScroll()
+ {
+ window.setTimeout(function() {
+ window.scrollTo(0, 200);
+ if (window.testRunner) {
+ document.getElementById('results').innerText = window.internals.scrollingStateTreeAsText(document);
+ testRunner.notifyDone();
+ }
+ }, 10);
+ }
+
+ window.addEventListener('load', doScroll, false);
+ </script>
+</head>
+<body>
+ <pre id="results"></pre>
+ <div class="scrolly">
+ <div class="fixed"></div>
+ <div class="big"></div>
+ </div>
+</body>
+</html>
--- /dev/null
+(Scrolling node
+ (viewport rect 0 0 785 600)
+ (contents size 785 1021)
+ (Scrolling on main thread because: Has non-layer fixed objects, )
+ (children 1
+ (Fixed node
+ (anchor edges: AnchorEdgeLeft AnchorEdgeTop)
+ (viewport rect at last layout: 0.00 0.00 785.00 600.00)
+ )
+ )
+)
+
--- /dev/null
+(Scrolling node
+ (viewport rect 0 0 785 600)
+ (contents size 785 1021)
+ (Scrolling on main thread because: Has non-layer fixed objects, )
+ (children 1
+ (Fixed node
+ (anchor edges: AnchorEdgeLeft AnchorEdgeTop)
+ (viewport rect at last layout: 0.00 0.00 785.00 600.00)
+ )
+ )
+)
+
--- /dev/null
+<!DOCTYPE html>
+
+<html>
+<head>
+ <style>
+ .fixed {
+ position: fixed;
+ width: 10px;
+ height: 10px;
+ }
+ </style>
+
+ <script type="text/javascript">
+ if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+
+ window.addEventListener("load", function() {
+ window.setTimeout(function() {
+ document.getElementById("scrollingTree").innerText = window.internals.scrollingStateTreeAsText(document);
+ testRunner.notifyDone();
+ }, 10);
+ }, false);
+ }
+ </script>
+</head>
+
+<body>
+ <div style="height: 1000px">
+ <pre id="scrollingTree"></pre>
+ </div>
+
+ <div class="fixed" style="z-index: -1; top: -100px"></div>
+ <div class="fixed" style="z-index: -1; top: 0px; left: 1000px"></div>
+
+ <div class="fixed" style="top: 0px; left: 0px"></div>
+</body>
+</html>
+
--- /dev/null
+<!DOCTYPE html>
+
+<html>
+<head>
+ <style>
+ .fixed {
+ position: fixed;
+ width: 10px;
+ height: 10px;
+ }
+ </style>
+
+ <script type="text/javascript">
+ if (window.testRunner)
+ testRunner.dumpAsText();
+
+ function doTest()
+ {
+ if (window.internals) {
+ document.getElementById('scrollingTree').innerText = internals.scrollingStateTreeAsText(document);
+ }
+ }
+ window.addEventListener('load', doTest, false);
+ </script>
+</head>
+
+<body>
+ <div style="height: 1000px">
+ <pre id="scrollingTree"></pre>
+ </div>
+
+ <div class="fixed" style="top: -100px"></div>
+ <div class="fixed" style="top: 0px; left: 1000px"></div>
+
+ <div class="fixed" style="top: 0px; left: 0px"></div>
+</body>
+</html>
+
--- /dev/null
+(Scrolling node
+ (viewport rect 0 0 785 600)
+ (contents size 785 2221)
+ (requested scroll position 0 200)
+ (children 4
+ (Fixed node
+ (anchor edges: AnchorEdgeLeft AnchorEdgeTop)
+ (viewport rect at last layout: 0.00 200.00 785.00 600.00)
+ )
+ (Fixed node
+ (anchor edges: AnchorEdgeLeft AnchorEdgeTop)
+ (viewport rect at last layout: 0.00 200.00 785.00 600.00)
+ (layer position at last layout 10.00 200.00)
+ )
+ (Fixed node
+ (anchor edges: AnchorEdgeRight AnchorEdgeTop)
+ (viewport rect at last layout: 0.00 200.00 785.00 600.00)
+ (layer position at last layout 601.00 200.00)
+ )
+ (Fixed node
+ (anchor edges: AnchorEdgeLeft AnchorEdgeBottom)
+ (viewport rect at last layout: 0.00 200.00 785.00 600.00)
+ (layer position at last layout 0.00 516.00)
+ )
+ )
+)
+This is the top bar. This is the left bar. This is the right bar. This is the bottom bar.
--- /dev/null
+<!DOCTYPE html>
+
+<html>
+<head>
+ <meta name="apple-mobile-web-app-capable" content="yes">
+ <style type="text/css" media="screen">
+ body {
+ height: 2200px;
+ }
+
+ .fixed {
+ position: fixed;
+ top: 0;
+ left: 0;
+ margin: 10px;
+ height: 50px;
+ background-color: rgba(0, 128, 0, 0.8);
+ border: 2px solid black;
+ -webkit-box-shadow: 0 0 10px black;
+ }
+
+ .top, .bottom {
+ width: 96%;
+ }
+
+ .left {
+ top: 200px;
+ left: 10px;
+ width: 150px;
+ height: 300px;
+ }
+
+ .right {
+ top: 200px;
+ left: auto;
+ right: 10px;
+ width: 150px;
+ height: 300px;
+ }
+
+ .bottom {
+ top: auto;
+ bottom: 10px;
+ }
+
+ </style>
+ <script type="text/javascript" charset="utf-8">
+ if (window.testRunner) {
+ testRunner.waitUntilDone();
+ testRunner.dumpAsText();
+ }
+
+ function doScroll()
+ {
+ window.setTimeout(function() {
+ window.scrollTo(0, 200);
+ if (window.testRunner) {
+ document.getElementById('results').innerText = window.internals.scrollingStateTreeAsText(document);
+ testRunner.notifyDone();
+ }
+ }, 10);
+ }
+
+ window.addEventListener('load', doScroll, false);
+ </script>
+</head>
+<body>
+
+<pre id="results"></pre>
+
+<div class="fixed top">
+ This is the top bar.
+</div>
+<div class="fixed left">
+ This is the left bar.
+</div>
+<div class="fixed right">
+ This is the right bar.
+</div>
+<div class="fixed bottom">
+ This is the bottom bar.
+</div>
+
+</body>
+</html>
--- /dev/null
+(Scrolling node
+ (viewport rect 0 0 785 600)
+ (contents size 785 2213)
+ (requested scroll position 0 200)
+ (children 1
+ (Fixed node
+ (anchor edges: AnchorEdgeLeft AnchorEdgeTop)
+ (viewport rect at last layout: 0.00 200.00 785.00 600.00)
+ )
+ )
+)
+
--- /dev/null
+<!DOCTYPE html>
+<html>
+
+<head>
+ <style type="text/css" media="screen">
+ body {
+ margin: 0;
+ height: 2200px;
+ }
+
+ .box {
+ height: 100px;
+ width: 100px;
+ }
+
+ .outer {
+ position: fixed;
+ top: 0px;
+ z-index: 1; /* makes this a stacking context */
+ background: blue;
+ }
+
+ .inner {
+ position: fixed;
+ top: 120px;
+ left: 120px;
+ background: green;
+ }
+ </style>
+ <script type="text/javascript" charset="utf-8">
+ if (window.testRunner) {
+ testRunner.waitUntilDone();
+ testRunner.dumpAsText();
+ }
+
+ function doScroll()
+ {
+ window.setTimeout(function() {
+ window.scrollTo(0, 200);
+ if (window.testRunner) {
+ document.getElementById('results').innerText = window.internals.scrollingStateTreeAsText(document);
+ testRunner.notifyDone();
+ }
+ }, 10);
+ }
+
+ window.addEventListener('load', doScroll, false);
+ </script>
+</head>
+<body>
+ <pre id="results"></pre>
+ <div class="outer box">
+ <div class="inner box"></div>
+ </div>
+</body>
+</html>
--- /dev/null
+(Scrolling node
+ (viewport rect 0 0 785 600)
+ (contents size 785 2513)
+ (requested scroll position 0 200)
+ (children 1
+ (Fixed node
+ (anchor edges: AnchorEdgeLeft AnchorEdgeTop)
+ (viewport rect at last layout: 0.00 200.00 785.00 600.00)
+ (layer position at last layout 0.00 13.00)
+ )
+ )
+)
+
--- /dev/null
+<!DOCTYPE html>
+<html>
+
+<head>
+ <style>
+ body {
+ margin: 0;
+ height: 2500px;
+ }
+
+ .box {
+ height: 100px;
+ width: 100px;
+ }
+
+ .wrapper {
+ position: fixed;
+ width: 50%;
+ height: 50%;
+ border: 20px solid gray;
+ background-color: silver;
+ z-index: 0;
+ }
+
+ .inner {
+ position: relative;
+ margin-left:-50px;
+ margin-top:-100px;
+ top: 100%;
+ left: 50%;
+ background: green;
+ }
+ </style>
+ <script>
+ if (window.testRunner) {
+ testRunner.waitUntilDone();
+ testRunner.dumpAsText();
+ }
+
+ function doScroll()
+ {
+ window.setTimeout(function() {
+ window.scrollTo(0, 200);
+ if (window.testRunner) {
+ document.getElementById('results').innerText = window.internals.scrollingStateTreeAsText(document);
+ testRunner.notifyDone();
+ }
+ }, 10);
+ }
+
+ window.addEventListener('load', doScroll, false);
+ </script>
+</head>
+<body>
+ <!-- The gray box should take up the top left quadrant of the web area.
+ The green box should be aligned with the inside edge of the paler gray box, in the bottom middle.
+ -->
+ <pre id="results"></pre>
+ <div class="wrapper">
+ <div class="inner box"></div>
+ </div>
+</body>
+</html>
(Scrolling node
(viewport rect 0 0 800 600)
(contents size 800 600)
- (Scrolling on main thread because: Has viewport constrained objects without supporting fixed layers, )
+ (Scrolling on main thread because: Has slow repaint objects, )
)
.box {
height: 100px;
width: 100px;
- position: fixed; /* At this time, position:fixed forces slow mode. */
+ background-image: -webkit-repeating-linear-gradient(red 10%, green 10%, green 30%);
+ background-attachment: fixed; /* At this time, background-attachment:fixed forces slow mode. */
}
</style>
<script>
(children 1
(GraphicsLayer
(visible rect 0.00, 0.00 0.00 x 0.00)
- (children 1
- (GraphicsLayer
- (position 8.00 13.00)
- (bounds 100.00 100.00)
- (visible rect 0.00, 0.00 100.00 x 100.00)
- )
- )
)
)
)
.box {
height: 100px;
width: 100px;
- position: fixed; /* At this time, position:fixed forces slow mode. */
+ background-image: -webkit-repeating-linear-gradient(red 10%, green 10%, green 30%);
+ background-attachment: fixed; /* At this time, background-attachment:fixed forces slow mode. */
}
</style>
<script>
+2012-11-05 Beth Dakin <bdakin@apple.com>
+
+ https://bugs.webkit.org/show_bug.cgi?id=101001
+ Pages with position:fixed elements should still be able to scroll on
+ the scrolling thread
+ -and corresponding-
+ <rdar://problem/10857315>
+
+ Reviewed by Simon Fraser.
+
+ This patch adds two new classes. ScrollingStateFixedNode is a class
+ to represent fixed nodes in the state tree, and
+ ScrollingTreeFixedNode represents fixed node in the scrolling tree
+ over on the scrolling thread.
+ * WebCore.xcodeproj/project.pbxproj:
+
+ When we are (non-programatically) scrolling fixed objects on the
+ scrolling thread, we do not want to do any work here.
+ * page/FrameView.cpp:
+ (WebCore::FrameView::updateFixedElementsAfterScrolling):
+
+ Whenever we sync the position of the main frame's layer, we have to
+ do the same for scrolling tree children.
+ * page/scrolling/ScrollingCoordinator.cpp:
+ (WebCore::ScrollingCoordinator::updateMainFrameScrollPosition):
+
+ New ScrollingNodeType -- FixedNode, yay! And two new functions
+ specific to dealing with FixedNodes.
+ * page/scrolling/ScrollingCoordinator.h:
+ (WebCore::ScrollingCoordinator::updateViewportConstrainedNode):
+ (WebCore::ScrollingCoordinator::syncChildPositions):
+
+ This is the new class that represents fixed nodes in the state tree.
+ All of the changed properties are stored within
+ FixedPositionViewportConstraints.
+ * page/scrolling/ScrollingStateFixedNode.cpp: Added.
+ (WebCore):
+ (WebCore::ScrollingStateFixedNode::create):
+ (WebCore::ScrollingStateFixedNode::ScrollingStateFixedNode):
+ (WebCore::ScrollingStateFixedNode::~ScrollingStateFixedNode):
+ (WebCore::ScrollingStateFixedNode::updateConstraints):
+ (WebCore::ScrollingStateFixedNode::dumpProperties):
+ * page/scrolling/ScrollingStateFixedNode.h: Added.
+ (WebCore):
+ (ScrollingStateFixedNode):
+ (WebCore::ScrollingStateFixedNode::viewportConstraints):
+ (WebCore::toScrollingStateFixedNode):
+
+ Make sure to create the right type of clone for each node.
+ * page/scrolling/ScrollingStateNode.cpp:
+ (WebCore::ScrollingStateNode::cloneAndReset):
+
+ Now that m_children may be anything other than null, I found this
+ bug. We encounter it when the parameter to removeChild is this and we
+ want to remove all of our children. In that case, this is obviously
+ not found in its own child array.
+ (WebCore::ScrollingStateNode::removeChild):
+
+ ScrollingStateNode now caches the GraphicsLayer in addition to the
+ PlatformLayer. This will allow us to sync the GraphicsLayer position
+ at the appropriate times.
+ * page/scrolling/ScrollingStateNode.h:
+ (WebCore::ScrollingStateNode::isScrollingStateFixedNode):
+ (WebCore::ScrollingStateNode::graphicsLayer):
+ (ScrollingStateNode):
+
+ Handle fixed nodes.
+ * page/scrolling/ScrollingTree.cpp:
+ (WebCore::ScrollingTree::updateTreeFromStateNode):
+
+ New function parentScrollPositionDidChange() is called on children
+ when the parent has scrolled.
+ * page/scrolling/ScrollingTreeNode.h:
+ (ScrollingTreeNode):
+ * page/scrolling/ScrollingTreeScrollingNode.h:
+ (ScrollingTreeScrollingNode):
+
+ Return true for supportsFixedPositionLayers().
+ * page/scrolling/mac/ScrollingCoordinatorMac.h:
+ (ScrollingCoordinatorMac):
+
+ Handle fixed nodes.
+ * page/scrolling/mac/ScrollingCoordinatorMac.mm:
+ (WebCore::ScrollingCoordinatorMac::attachToStateTree):
+
+ Now that m_children can be non-null I caught this pre-existing bug
+ where we would come times remove a node without updating the HashMap.
+ This patch fixes that by consolidating the removal into one function.
+ (WebCore::ScrollingCoordinatorMac::removeNode):
+ (WebCore::ScrollingCoordinatorMac::detachFromStateTree):
+ (WebCore::ScrollingCoordinatorMac::clearStateTree):
+
+ Update the GraphicsLayers to reflect the new position that the
+ Scrolling thread has moved the underlying CALayer to already.
+ (WebCore::ScrollingCoordinatorMac::syncChildPositions):
+
+ Pass new constraints over to the appropriate state node.
+ (WebCore::ScrollingCoordinatorMac::updateViewportConstrainedNode):
+
+ Cache the GraphicsLayer in addition to the PlatformLayer.
+ * page/scrolling/mac/ScrollingStateNodeMac.mm:
+ (WebCore::ScrollingStateNode::setScrollLayer):
+
+ Here is the new class that represents fixed nodes over on the
+ scrolling thread.
+ * page/scrolling/mac/ScrollingTreeFixedNode.h: Added.
+ (WebCore):
+ (ScrollingTreeFixedNode):
+ * page/scrolling/mac/ScrollingTreeFixedNode.mm: Added.
+ (WebCore):
+ (WebCore::ScrollingTreeFixedNode::create):
+ (WebCore::ScrollingTreeFixedNode::ScrollingTreeFixedNode):
+ (WebCore::ScrollingTreeFixedNode::~ScrollingTreeFixedNode):
+ (WebCore::ScrollingTreeFixedNode::update):
+
+ This is where the magic happens. re-position the fixed object when
+ its parent has scrolled so that it appears to have not moved at all.
+ (WebCore::ScrollingTreeFixedNode::parentScrollPositionDidChange):
+
+ Whenever we change the position of a scrolling layer, tell our
+ children.
+ * page/scrolling/mac/ScrollingTreeScrollingNodeMac.mm:
+ (WebCore::ScrollingTreeScrollingNodeMac::setScrollLayerPosition):
+
+ Handle fixed nodes.
+ * rendering/RenderLayerBacking.cpp:
+ (WebCore::RenderLayerBacking::attachToScrollingCoordinator):
+
+ detachFromScrollingCoordinator() needs to be public so that it can be
+ called from RenderLayerCompositor for fixed nodes.
+ * rendering/RenderLayerBacking.h:
+ (RenderLayerBacking):
+
+ RenderLayerCompositor takes control of attaching and detaching fixed
+ nodes to/from the ScrollingCoordinator.
+ * rendering/RenderLayerCompositor.cpp:
+ (WebCore::RenderLayerCompositor::flushPendingLayerChanges):
+ (WebCore::RenderLayerCompositor::didFlushChangesForLayer):
+ (WebCore::RenderLayerCompositor::updateBacking):
+ (WebCore::RenderLayerCompositor::layerWillBeRemoved):
+ (WebCore::RenderLayerCompositor::didMoveOnscreen):
+ (WebCore::RenderLayerCompositor::willMoveOffscreen):
+ (WebCore::RenderLayerCompositor::clearBackingForLayerIncludingDescendants):
+ (WebCore::isRootmostFixedOrStickyLayer):
+ (WebCore):
+ (WebCore::RenderLayerCompositor::updateViewportConstraintStatus):
+ (WebCore::RenderLayerCompositor::addViewportConstrainedLayer):
+ (WebCore::RenderLayerCompositor::removeViewportConstrainedLayer):
+ (WebCore::RenderLayerCompositor::computeViewportConstraints):
+ (WebCore::nearestScrollingCoordinatorAncestor):
+ (WebCore::RenderLayerCompositor::registerOrUpdateViewportConstrainedLayer):
+ (WebCore::RenderLayerCompositor::unregisterViewportConstrainedLayer):
+ (WebCore::RenderLayerCompositor::registerAllViewportConstrainedLayers):
+ (WebCore::RenderLayerCompositor::unregisterAllViewportConstrainedLayers):
+ * rendering/RenderLayerCompositor.h:
+ (WebCore):
+ (RenderLayerCompositor):
+
2012-11-05 Geoffrey Garen <ggaren@apple.com>
Cleaned up the Font class in preparation for optimizing kerning and ligatures
93C09A7F0B064EEF005ABD4D /* EventHandlerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 93C09A7E0B064EEF005ABD4D /* EventHandlerMac.mm */; };
93C09A810B064F00005ABD4D /* EventHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93C09A800B064F00005ABD4D /* EventHandler.cpp */; };
93C09C860B0657AA005ABD4D /* ScrollTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 93C09C850B0657AA005ABD4D /* ScrollTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 93C38BFE164473C700091EB2 /* ScrollingStateFixedNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93C38BFC164473C700091EB2 /* ScrollingStateFixedNode.cpp */; };
+ 93C38BFF164473C700091EB2 /* ScrollingStateFixedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 93C38BFD164473C700091EB2 /* ScrollingStateFixedNode.h */; };
+ 93C38C03164473DD00091EB2 /* ScrollingTreeFixedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 93C38C01164473DD00091EB2 /* ScrollingTreeFixedNode.h */; };
+ 93C38C04164473DD00091EB2 /* ScrollingTreeFixedNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 93C38C02164473DD00091EB2 /* ScrollingTreeFixedNode.mm */; };
93C442000F813AE100C1A634 /* CollectionType.h in Headers */ = {isa = PBXBuildFile; fileRef = 93C441FF0F813AE100C1A634 /* CollectionType.h */; settings = {ATTRIBUTES = (Private, ); }; };
93C4A4151629DF5A00C3EB6E /* ScrollingTreeScrollingNodeMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 93C4A4131629DF5A00C3EB6E /* ScrollingTreeScrollingNodeMac.h */; };
93C4A4161629DF5A00C3EB6E /* ScrollingTreeScrollingNodeMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 93C4A4141629DF5A00C3EB6E /* ScrollingTreeScrollingNodeMac.mm */; };
93C09A7E0B064EEF005ABD4D /* EventHandlerMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EventHandlerMac.mm; sourceTree = "<group>"; };
93C09A800B064F00005ABD4D /* EventHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventHandler.cpp; sourceTree = "<group>"; };
93C09C850B0657AA005ABD4D /* ScrollTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollTypes.h; sourceTree = "<group>"; };
+ 93C38BFC164473C700091EB2 /* ScrollingStateFixedNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScrollingStateFixedNode.cpp; sourceTree = "<group>"; };
+ 93C38BFD164473C700091EB2 /* ScrollingStateFixedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollingStateFixedNode.h; sourceTree = "<group>"; };
+ 93C38C01164473DD00091EB2 /* ScrollingTreeFixedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollingTreeFixedNode.h; sourceTree = "<group>"; };
+ 93C38C02164473DD00091EB2 /* ScrollingTreeFixedNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ScrollingTreeFixedNode.mm; sourceTree = "<group>"; };
93C441FF0F813AE100C1A634 /* CollectionType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollectionType.h; sourceTree = "<group>"; };
93C4A4131629DF5A00C3EB6E /* ScrollingTreeScrollingNodeMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollingTreeScrollingNodeMac.h; sourceTree = "<group>"; };
93C4A4141629DF5A00C3EB6E /* ScrollingTreeScrollingNodeMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ScrollingTreeScrollingNodeMac.mm; sourceTree = "<group>"; };
0F605AEB15F94848004DF0C0 /* ScrollingConstraints.h */,
1AF62EE414DA22A70041556C /* ScrollingCoordinator.cpp */,
1AF62EE514DA22A70041556C /* ScrollingCoordinator.h */,
+ 93C38BFC164473C700091EB2 /* ScrollingStateFixedNode.cpp */,
+ 93C38BFD164473C700091EB2 /* ScrollingStateFixedNode.h */,
931CBD06161A44E900E4C874 /* ScrollingStateNode.cpp */,
931CBD07161A44E900E4C874 /* ScrollingStateNode.h */,
931CBD08161A44E900E4C874 /* ScrollingStateScrollingNode.cpp */,
1AF62EE314DA22A70041556C /* ScrollingCoordinatorMac.mm */,
931CBD12161A44F800E4C874 /* ScrollingStateNodeMac.mm */,
1AF62F2314DAFE910041556C /* ScrollingThreadMac.mm */,
+ 93C38C01164473DD00091EB2 /* ScrollingTreeFixedNode.h */,
+ 93C38C02164473DD00091EB2 /* ScrollingTreeFixedNode.mm */,
1A35862A152522540022A659 /* ScrollingTreeMac.mm */,
93C4A4131629DF5A00C3EB6E /* ScrollingTreeScrollingNodeMac.h */,
93C4A4141629DF5A00C3EB6E /* ScrollingTreeScrollingNodeMac.mm */,
50933350163B0E4300099A60 /* CustomFilterParameterList.h in Headers */,
50D32858163B313F0016111E /* ValidatedCustomFilterOperation.h in Headers */,
3FFFF9A9159D9A550020BBD5 /* WebKitCSSViewportRule.h in Headers */,
+ 93C38BFF164473C700091EB2 /* ScrollingStateFixedNode.h in Headers */,
+ 93C38C03164473DD00091EB2 /* ScrollingTreeFixedNode.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
3FFFF9A8159D9A550020BBD5 /* WebKitCSSViewportRule.cpp in Sources */,
4FFC022B1643B710004E1638 /* NodeRareData.cpp in Sources */,
4FFC022D1643B726004E1638 /* ElementRareData.cpp in Sources */,
+ 93C38BFE164473C700091EB2 /* ScrollingStateFixedNode.cpp in Sources */,
+ 93C38C04164473DD00091EB2 /* ScrollingTreeFixedNode.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
}
}
+bool FrameView::shouldUpdateFixedElementsAfterScrolling()
+{
+#if ENABLE(THREADED_SCROLLING)
+ Page* page = m_frame->page();
+ if (!page)
+ return true;
+
+ // If the scrolling thread is updating the fixed elements, then the FrameView should not update them as well.
+ if (page->mainFrame() != m_frame)
+ return true;
+
+ ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator();
+ if (!scrollingCoordinator)
+ return true;
+
+ if (!scrollingCoordinator->supportsFixedPositionLayers())
+ return true;
+
+ if (scrollingCoordinator->shouldUpdateScrollLayerPositionOnMainThread())
+ return true;
+
+ if (inProgrammaticScroll())
+ return true;
+
+ return false;
+#endif
+ return true;
+}
+
void FrameView::updateFixedElementsAfterScrolling()
{
#if USE(ACCELERATED_COMPOSITING)
+ if (!shouldUpdateFixedElementsAfterScrolling())
+ return;
+
if (m_nestedLayoutCount <= 1 && hasViewportConstrainedObjects()) {
- if (RenderView* root = rootRenderer(this)) {
+ if (RenderView* root = rootRenderer(this))
root->compositor()->updateCompositingLayers(CompositingUpdateOnScroll);
- }
}
#endif
}
void updateCanBlitOnScrollRecursively();
bool contentsInCompositedLayer() const;
+ bool shouldUpdateFixedElementsAfterScrolling();
+
void applyOverflowToViewport(RenderObject*, ScrollbarMode& hMode, ScrollbarMode& vMode);
void applyPaginationToViewport();
AnchorEdgeBottom = 1 << 3
};
typedef unsigned AnchorEdges;
-
- ViewportConstraints()
- : m_anchorEdges(0)
- { }
-
- ViewportConstraints(ViewportConstraints* constraints)
- : m_alignmentOffset(constraints->alignmentOffset())
- , m_anchorEdges(constraints->anchorEdges())
- { }
virtual ~ViewportConstraints() { }
void setAlignmentOffset(const FloatSize& offset) { m_alignmentOffset = offset; }
protected:
+ ViewportConstraints()
+ : m_anchorEdges(0)
+ { }
+
+ ViewportConstraints(const ViewportConstraints& constraints)
+ : m_alignmentOffset(constraints.alignmentOffset())
+ , m_anchorEdges(constraints.anchorEdges())
+ { }
+
FloatSize m_alignmentOffset;
AnchorEdges m_anchorEdges;
};
FixedPositionViewportConstraints()
{ }
- FixedPositionViewportConstraints(FixedPositionViewportConstraints* constraints)
+ FixedPositionViewportConstraints(const FixedPositionViewportConstraints& constraints)
: ViewportConstraints(constraints)
- , m_viewportRectAtLastLayout(constraints->viewportRectAtLastLayout())
- , m_layerPositionAtLastLayout(constraints->layerPositionAtLastLayout())
+ , m_viewportRectAtLastLayout(constraints.viewportRectAtLastLayout())
+ , m_layerPositionAtLastLayout(constraints.layerPositionAtLastLayout())
{ }
virtual ConstraintType constraintType() const OVERRIDE { return FixedPositionConstaint; };
const FloatPoint& layerPositionAtLastLayout() const { return m_layerPositionAtLastLayout; }
void setLayerPositionAtLastLayout(const FloatPoint& point) { m_layerPositionAtLastLayout = point; }
+ bool operator==(const FixedPositionViewportConstraints& other) const
+ {
+ return m_alignmentOffset == other.m_alignmentOffset
+ && m_anchorEdges == other.m_anchorEdges
+ && m_viewportRectAtLastLayout == other.m_viewportRectAtLastLayout
+ && m_layerPositionAtLastLayout == other.m_layerPositionAtLastLayout;
+ }
+
+ bool operator!=(const FixedPositionViewportConstraints& other) const { return !(*this == other); }
+
private:
FloatRect m_viewportRectAtLastLayout;
FloatPoint m_layerPositionAtLastLayout;
if (GraphicsLayer* scrollLayer = scrollLayerForFrameView(frameView)) {
if (programmaticScroll)
scrollLayer->setPosition(-frameView->scrollPosition());
- else
+ else {
scrollLayer->syncPosition(-frameView->scrollPosition());
+ syncChildPositions(frameView->visibleContentRect());
+ }
}
#endif
}
#define ScrollingCoordinator_h
#include "IntRect.h"
+#include "LayoutTypes.h"
#include "PlatformWheelEvent.h"
#include "ScrollTypes.h"
#include "Timer.h"
typedef unsigned MainThreadScrollingReasons;
typedef uint64_t ScrollingNodeID;
-enum ScrollingNodeType {
- ScrollingNode
- // FIXME: This will soon contain other types such as FixedNode.
-};
+enum ScrollingNodeType { ScrollingNode, FixedNode };
class Frame;
class FrameView;
class Page;
class Region;
class ScrollableArea;
-class ScrollingStateNode;
-class ScrollingStateScrollingNode;
-class ScrollingStateTree;
+class ViewportConstraints;
#if ENABLE(THREADED_SCROLLING)
class ScrollingTree;
virtual ScrollingNodeID attachToStateTree(ScrollingNodeType, ScrollingNodeID newNodeID, ScrollingNodeID /*parentID*/) { return newNodeID; }
virtual void detachFromStateTree(ScrollingNodeID) { }
virtual void clearStateTree() { }
+ virtual void updateViewportConstrainedNode(ScrollingNodeID, const ViewportConstraints&, GraphicsLayer*) { }
+ virtual void syncChildPositions(const LayoutRect&) { }
virtual String scrollingStateTreeAsText() const;
// Generated a unique id for scroll layers.
--- /dev/null
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollingStateFixedNode.h"
+
+#include "ScrollingStateTree.h"
+#include "TextStream.h"
+#include <wtf/OwnPtr.h>
+
+#if ENABLE(THREADED_SCROLLING)
+
+namespace WebCore {
+
+PassOwnPtr<ScrollingStateFixedNode> ScrollingStateFixedNode::create(ScrollingStateTree* stateTree, ScrollingNodeID nodeID)
+{
+ return adoptPtr(new ScrollingStateFixedNode(stateTree, nodeID));
+}
+
+ScrollingStateFixedNode::ScrollingStateFixedNode(ScrollingStateTree* tree, ScrollingNodeID nodeID)
+ : ScrollingStateNode(tree, nodeID)
+ , m_changedProperties(0)
+{
+}
+
+ScrollingStateFixedNode::ScrollingStateFixedNode(const ScrollingStateFixedNode& node)
+ : ScrollingStateNode(node)
+ , m_constraints(FixedPositionViewportConstraints(node.viewportConstraints()))
+ , m_changedProperties(node.changedProperties())
+{
+}
+
+ScrollingStateFixedNode::~ScrollingStateFixedNode()
+{
+}
+
+PassOwnPtr<ScrollingStateNode> ScrollingStateFixedNode::clone()
+{
+ return adoptPtr(new ScrollingStateFixedNode(*this));
+}
+
+void ScrollingStateFixedNode::updateConstraints(const FixedPositionViewportConstraints& constraints)
+{
+ if (m_constraints == constraints)
+ return;
+
+ m_constraints = constraints;
+ m_changedProperties = ViewportConstraints;
+ m_scrollingStateTree->setHasChangedProperties(true);
+}
+
+void ScrollingStateFixedNode::dumpProperties(TextStream& ts, int indent) const
+{
+ ts << "(" << "Fixed node" << "\n";
+
+ if (m_constraints.anchorEdges()) {
+ writeIndent(ts, indent + 1);
+ ts << "(anchor edges: ";
+ if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeLeft))
+ ts << "AnchorEdgeLeft ";
+ if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeRight))
+ ts << "AnchorEdgeRight ";
+ if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeTop))
+ ts << "AnchorEdgeTop";
+ if (m_constraints.hasAnchorEdge(ViewportConstraints::AnchorEdgeBottom))
+ ts << "AnchorEdgeBottom";
+ ts << ")\n";
+ }
+
+ if (!m_constraints.alignmentOffset().isEmpty()) {
+ writeIndent(ts, indent + 1);
+ ts << "(alignment offset " << m_constraints.alignmentOffset().width() << " " << m_constraints.alignmentOffset().height() << ")\n";
+ }
+
+ if (!m_constraints.viewportRectAtLastLayout().isEmpty()) {
+ writeIndent(ts, indent + 1);
+ FloatRect viewportRect = m_constraints.viewportRectAtLastLayout();
+ ts << "(viewport rect at last layout: " << viewportRect.x() << " " << viewportRect.y() << " " << viewportRect.width() << " " << viewportRect.height() << ")\n";
+ }
+
+ if (m_constraints.layerPositionAtLastLayout() != FloatPoint()) {
+ writeIndent(ts, indent + 1);
+ ts << "(layer position at last layout " << m_constraints.layerPositionAtLastLayout().x() << " " << m_constraints.layerPositionAtLastLayout().y() << ")\n";
+ }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(THREADED_SCROLLING)
--- /dev/null
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ScrollingStateFixedNode_h
+#define ScrollingStateFixedNode_h
+
+#if ENABLE(THREADED_SCROLLING)
+
+#include "ScrollingConstraints.h"
+#include "ScrollingStateNode.h"
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class FixedPositionViewportConstraints;
+
+class ScrollingStateFixedNode : public ScrollingStateNode {
+public:
+ static PassOwnPtr<ScrollingStateFixedNode> create(ScrollingStateTree*, ScrollingNodeID);
+
+ virtual PassOwnPtr<ScrollingStateNode> clone();
+
+ virtual ~ScrollingStateFixedNode();
+
+ enum ChangedPropertyForFixed {
+ ViewportConstraints = 1 << 0
+ };
+
+ virtual unsigned changedProperties() const OVERRIDE { return m_changedProperties; }
+
+ void updateConstraints(const FixedPositionViewportConstraints&);
+ const FixedPositionViewportConstraints& viewportConstraints() const { return m_constraints; }
+
+private:
+ ScrollingStateFixedNode(ScrollingStateTree*, ScrollingNodeID);
+ ScrollingStateFixedNode(const ScrollingStateFixedNode&);
+
+ virtual bool isFixedNode() OVERRIDE { return true; }
+
+ virtual bool hasChangedProperties() const OVERRIDE { return m_changedProperties; }
+ virtual void resetChangedProperties() OVERRIDE { m_changedProperties = 0; }
+
+ virtual void dumpProperties(TextStream&, int indent) const OVERRIDE;
+
+ FixedPositionViewportConstraints m_constraints;
+ unsigned m_changedProperties;
+};
+
+inline ScrollingStateFixedNode* toScrollingStateFixedNode(ScrollingStateNode* node)
+{
+ ASSERT(!node || node->isFixedNode());
+ return static_cast<ScrollingStateFixedNode*>(node);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toScrollingStateFixedNode(const ScrollingStateFixedNode*);
+
+} // namespace WebCore
+
+#endif // ENABLE(THREADED_SCROLLING)
+
+#endif // ScrollingStateFixedNode_h
#include "config.h"
#include "ScrollingStateNode.h"
+#include "ScrollingStateFixedNode.h"
#include "ScrollingStateTree.h"
#include "TextStream.h"
PassOwnPtr<ScrollingStateNode> ScrollingStateNode::cloneAndReset()
{
- OwnPtr<ScrollingStateScrollingNode> clone = adoptPtr(new ScrollingStateScrollingNode(*toScrollingStateScrollingNode(this)));
+ OwnPtr<ScrollingStateNode> clone = this->clone();
// Now that this node is cloned, reset our change properties.
setScrollLayerDidChange(false);
if (!m_children)
return;
- if (size_t index = m_children->find(node)) {
+ size_t index = m_children->find(node);
+
+ // The index will be notFound if the node to remove is a deeper-than-1-level descendant or
+ // if node is the root state node.
+ if (index != notFound) {
m_scrollingStateTree->didRemoveNode(node->scrollingNodeID());
m_children->remove(index);
return;
ScrollingStateNode(ScrollingStateTree*, ScrollingNodeID);
virtual ~ScrollingStateNode();
- virtual bool isScrollingStateScrollingNode() { return false; }
+ virtual bool isScrollingNode() { return false; }
+ virtual bool isFixedNode() { return false; }
+ virtual PassOwnPtr<ScrollingStateNode> clone() = 0;
PassOwnPtr<ScrollingStateNode> cloneAndReset();
void cloneAndResetChildren(ScrollingStateNode*);
virtual void resetChangedProperties() = 0;
virtual void setHasChangedProperties() { setScrollLayerDidChange(true); }
+ GraphicsLayer* graphicsLayer() { return m_graphicsLayer; }
PlatformLayer* platformScrollLayer() const;
- void setScrollLayer(const GraphicsLayer*);
+ void setScrollLayer(GraphicsLayer*);
void setScrollLayer(PlatformLayer*);
bool scrollLayerDidChange() const { return m_scrollLayerDidChange; }
#if PLATFORM(MAC)
RetainPtr<PlatformLayer> m_platformScrollLayer;
#endif
+ GraphicsLayer* m_graphicsLayer;
};
{
}
+PassOwnPtr<ScrollingStateNode> ScrollingStateScrollingNode::clone()
+{
+ return adoptPtr(new ScrollingStateScrollingNode(*this));
+}
+
void ScrollingStateScrollingNode::setViewportRect(const IntRect& viewportRect)
{
if (m_viewportRect == viewportRect)
public:
static PassOwnPtr<ScrollingStateScrollingNode> create(ScrollingStateTree*, ScrollingNodeID);
- ScrollingStateScrollingNode(const ScrollingStateScrollingNode&);
+ virtual PassOwnPtr<ScrollingStateNode> clone();
+
virtual ~ScrollingStateScrollingNode();
enum ChangedProperty {
RequestedScrollPosition = 1 << 12,
};
- virtual bool isScrollingStateScrollingNode() OVERRIDE { return true; }
+ virtual bool isScrollingNode() OVERRIDE { return true; }
virtual bool hasChangedProperties() const OVERRIDE { return m_changedProperties; }
virtual unsigned changedProperties() const OVERRIDE { return m_changedProperties; }
private:
ScrollingStateScrollingNode(ScrollingStateTree*, ScrollingNodeID);
+ ScrollingStateScrollingNode(const ScrollingStateScrollingNode&);
unsigned m_changedProperties;
inline ScrollingStateScrollingNode* toScrollingStateScrollingNode(ScrollingStateNode* node)
{
- ASSERT(!node || node->isScrollingStateScrollingNode());
+ ASSERT(!node || node->isScrollingNode());
return static_cast<ScrollingStateScrollingNode*>(node);
}
#include "ScrollingCoordinator.h"
#include "ScrollingStateTree.h"
#include "ScrollingThread.h"
+#include "ScrollingTreeFixedNode.h"
#include "ScrollingTreeNode.h"
#include "ScrollingTreeScrollingNode.h"
#include <wtf/MainThread.h>
m_nodeMap.set(stateNode->scrollingNodeID(), m_rootNode.get());
m_rootNode->update(stateNode);
} else {
- // FIXME: In the future, we will have more than just ScrollingTreeScrollingNode, so we'll have to
- // figure out which type of node to create.
- OwnPtr<ScrollingTreeNode> newNode = ScrollingTreeScrollingNode::create(this);
+ OwnPtr<ScrollingTreeNode> newNode;
+ if (stateNode->isScrollingNode())
+ newNode = ScrollingTreeScrollingNode::create(this);
+ else if (stateNode->isFixedNode())
+ newNode = ScrollingTreeFixedNode::create(this);
+ else
+ ASSERT_NOT_REACHED();
ScrollingTreeNode* newNodeRawPtr = newNode.get();
m_nodeMap.set(stateNode->scrollingNodeID(), newNodeRawPtr);
ScrollingTreeNodeMap::const_iterator it = m_nodeMap.find(stateNode->parent()->scrollingNodeID());
namespace WebCore {
class IntPoint;
+class ScrollingStateNode;
+class ScrollingStateTree;
class ScrollingTreeNode;
class ScrollingTreeScrollingNode;
-class ScrollingStateTree;
// The ScrollingTree class lives almost exclusively on the scrolling thread and manages the
// hierarchy of scrollable regions on the page. It's also responsible for dispatching events
namespace WebCore {
+class ScrollingStateFixedNode;
+class ScrollingStateNode;
+class ScrollingStateScrollingNode;
+
class ScrollingTreeNode {
public:
explicit ScrollingTreeNode(ScrollingTree*);
virtual void update(ScrollingStateNode*) = 0;
+ virtual void parentScrollPositionDidChange(const IntRect& viewportRect) = 0;
+
ScrollingNodeID scrollingNodeID() const { return m_nodeID; }
void setScrollingNodeID(ScrollingNodeID nodeID) { m_nodeID = nodeID; }
protected:
ScrollingTree* scrollingTree() const { return m_scrollingTree; }
+ typedef Vector<OwnPtr<ScrollingTreeNode> > ScrollingTreeChildrenVector;
+ OwnPtr<ScrollingTreeChildrenVector> m_children;
+
private:
ScrollingTree* m_scrollingTree;
ScrollingNodeID m_nodeID;
ScrollingTreeNode* m_parent;
- OwnPtr<Vector<OwnPtr<ScrollingTreeNode> > > m_children;
};
} // namespace WebCore
virtual ~ScrollingTreeScrollingNode();
virtual void update(ScrollingStateNode*) OVERRIDE;
+
+ // FIXME: We should implement this when we support ScrollingTreeScrollingNodes as children.
+ virtual void parentScrollPositionDidChange(const IntRect& /*viewportRect*/) OVERRIDE { }
+
virtual void handleWheelEvent(const PlatformWheelEvent&) = 0;
virtual void setScrollPosition(const IntPoint&) = 0;
namespace WebCore {
+class ScrollingStateNode;
+class ScrollingStateScrollingNode;
+class ScrollingStateTree;
+
class ScrollingCoordinatorMac : public ScrollingCoordinator {
public:
explicit ScrollingCoordinatorMac(Page*);
virtual String scrollingStateTreeAsText() const OVERRIDE;
private:
+ // Return whether this scrolling coordinator can keep fixed position layers fixed to their
+ // containers while scrolling.
+ virtual bool supportsFixedPositionLayers() const OVERRIDE { return true; }
+
+ // This function will update the ScrollingStateNode for the given viewport constrained object.
+ virtual void updateViewportConstrainedNode(ScrollingNodeID, const ViewportConstraints&, GraphicsLayer*) OVERRIDE;
+
+ // Called to synch the GraphicsLayer positions for child layers when their CALayers have been moved by the scrolling thread.
+ virtual void syncChildPositions(const LayoutRect& viewportRect) OVERRIDE;
+
virtual void recomputeWheelEventHandlerCountForFrameView(FrameView*);
virtual void setShouldUpdateScrollLayerPositionOnMainThread(MainThreadScrollingReasons);
void scrollingStateTreeCommitterTimerFired(Timer<ScrollingCoordinatorMac>*);
void commitTreeState();
+ void removeNode(ScrollingStateNode*);
+
OwnPtr<ScrollingStateTree> m_scrollingStateTree;
RefPtr<ScrollingTree> m_scrollingTree;
Timer<ScrollingCoordinatorMac> m_scrollingStateTreeCommitterTimer;
#include "RenderLayerCompositor.h"
#include "RenderView.h"
#include "ScrollAnimator.h"
+#include "ScrollingConstraints.h"
+#include "ScrollingStateFixedNode.h"
#include "ScrollingStateScrollingNode.h"
#include "ScrollingStateTree.h"
#include "ScrollingThread.h"
} else {
ScrollingStateNode* parent = stateNodeForID(parentID);
switch (nodeType) {
+ case FixedNode: {
+ ASSERT(supportsFixedPositionLayers());
+ OwnPtr<ScrollingStateFixedNode> fixedNode = ScrollingStateFixedNode::create(m_scrollingStateTree.get(), newNodeID);
+ newNode = fixedNode.get();
+ parent->appendChild(fixedNode.release());
+ break;
+ }
case ScrollingNode: {
- // FIXME: We currently do not support child nodes. This assertion should be removed when we do.
+ // FIXME: We currently only support child nodes that are fixed.
ASSERT_NOT_REACHED();
- PassOwnPtr<ScrollingStateScrollingNode> scrollingNode = ScrollingStateScrollingNode::create(m_scrollingStateTree.get(), newNodeID);
+ OwnPtr<ScrollingStateScrollingNode> scrollingNode = ScrollingStateScrollingNode::create(m_scrollingStateTree.get(), newNodeID);
newNode = scrollingNode.get();
- parent->appendChild(scrollingNode);
+ parent->appendChild(scrollingNode.release());
break;
}
default:
return newNodeID;
}
+void ScrollingCoordinatorMac::removeNode(ScrollingStateNode* node)
+{
+ m_scrollingStateTree->removeNode(node);
+
+ // ScrollingStateTree::removeNode() will destroy children, so we have to make sure we remove those children
+ // from the HashMap.
+ const Vector<ScrollingNodeID>& removedNodes = m_scrollingStateTree->removedNodes();
+ size_t size = removedNodes.size();
+ for (size_t i = 0; i < size; ++i)
+ m_stateNodeMap.remove(removedNodes[i]);
+}
+
void ScrollingCoordinatorMac::detachFromStateTree(ScrollingNodeID scrollLayerID)
{
if (!scrollLayerID)
if (!node)
return;
- m_scrollingStateTree->removeNode(node);
-
- // ScrollingStateTree::removeNode() will destroy children, so we have to make sure we remove those children
- // from the HashMap.
- const Vector<ScrollingNodeID>& removedNodes = m_scrollingStateTree->removedNodes();
- size_t size = removedNodes.size();
- for (size_t i = 0; i < size; ++i)
- m_stateNodeMap.remove(removedNodes[i]);
+ removeNode(node);
}
void ScrollingCoordinatorMac::clearStateTree()
{
- m_stateNodeMap.clear();
- m_scrollingStateTree->removeNode(m_scrollingStateTree->rootStateNode());
+ removeNode(m_scrollingStateTree->rootStateNode());
}
ScrollingStateNode* ScrollingCoordinatorMac::stateNodeForID(ScrollingNodeID scrollLayerID)
scrollLayer->setPosition(-frameView->scrollPosition());
}
+void ScrollingCoordinatorMac::syncChildPositions(const LayoutRect& viewportRect)
+{
+ Vector<OwnPtr<ScrollingStateNode> >* children = m_scrollingStateTree->rootStateNode()->children();
+ if (!children)
+ return;
+
+ // FIXME: We'll have to traverse deeper into the tree at some point.
+ size_t size = children->size();
+ for (size_t i = 0; i < size; ++i) {
+ ScrollingStateFixedNode* child = toScrollingStateFixedNode(children->at(i).get());
+ FloatPoint position = child->viewportConstraints().layerPositionForViewportRect(viewportRect);
+ child->graphicsLayer()->setPosition(position);
+ }
+}
+
+void ScrollingCoordinatorMac::updateViewportConstrainedNode(ScrollingNodeID nodeID, const ViewportConstraints& constraints, GraphicsLayer* graphicsLayer)
+{
+ ASSERT(supportsFixedPositionLayers());
+
+ // FIXME: We should support sticky position here!
+ if (constraints.constraintType() == ViewportConstraints::StickyPositionConstraint)
+ return;
+
+ ScrollingStateFixedNode* node = toScrollingStateFixedNode(stateNodeForID(nodeID));
+ setScrollLayerForNode(graphicsLayer, node);
+ node->updateConstraints((const FixedPositionViewportConstraints&)constraints);
+}
+
void ScrollingCoordinatorMac::scheduleTreeStateCommit()
{
if (m_scrollingStateTreeCommitterTimer.isActive())
m_platformScrollLayer = platformLayer;
}
-void ScrollingStateNode::setScrollLayer(const GraphicsLayer* graphicsLayer)
+void ScrollingStateNode::setScrollLayer(GraphicsLayer* graphicsLayer)
{
PlatformLayer* platformScrollLayer = graphicsLayer ? graphicsLayer->platformLayer() : nil;
return;
m_platformScrollLayer = platformScrollLayer;
+ m_graphicsLayer = graphicsLayer;
+
m_scrollLayerDidChange = true;
m_scrollingStateTree->setHasChangedProperties(true);
}
--- /dev/null
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ScrollingTreeFixedNode_h
+#define ScrollingTreeFixedNode_h
+
+#if ENABLE(THREADED_SCROLLING)
+
+#include "ScrollingConstraints.h"
+#include "ScrollingTreeNode.h"
+#include <wtf/RetainPtr.h>
+
+OBJC_CLASS CALayer;
+
+namespace WebCore {
+
+class FixedPositionViewportConstraints;
+
+class ScrollingTreeFixedNode : public ScrollingTreeNode {
+public:
+ static PassOwnPtr<ScrollingTreeFixedNode> create(ScrollingTree*);
+
+ virtual ~ScrollingTreeFixedNode();
+
+private:
+ ScrollingTreeFixedNode(ScrollingTree*);
+
+ virtual void update(ScrollingStateNode*) OVERRIDE;
+ virtual void parentScrollPositionDidChange(const IntRect& viewportRect) OVERRIDE;
+
+ FixedPositionViewportConstraints m_constraints;
+ RetainPtr<CALayer> m_layer;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(THREADED_SCROLLING)
+
+#endif // ScrollingTreeFixedNode_h
--- /dev/null
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollingTreeFixedNode.h"
+
+#if ENABLE(THREADED_SCROLLING)
+
+#include "ScrollingStateFixedNode.h"
+#include "ScrollingTree.h"
+
+namespace WebCore {
+
+PassOwnPtr<ScrollingTreeFixedNode> ScrollingTreeFixedNode::create(ScrollingTree* scrollingTree)
+{
+ return adoptPtr(new ScrollingTreeFixedNode(scrollingTree));
+}
+
+ScrollingTreeFixedNode::ScrollingTreeFixedNode(ScrollingTree* scrollingTree)
+ : ScrollingTreeNode(scrollingTree)
+ , m_constraints(FixedPositionViewportConstraints())
+{
+}
+
+ScrollingTreeFixedNode::~ScrollingTreeFixedNode()
+{
+}
+
+void ScrollingTreeFixedNode::update(ScrollingStateNode* stateNode)
+{
+ ScrollingStateFixedNode* state = toScrollingStateFixedNode(stateNode);
+
+ if (state->scrollLayerDidChange())
+ m_layer = state->platformScrollLayer();
+
+ if (stateNode->changedProperties() & ScrollingStateFixedNode::ViewportConstraints)
+ m_constraints = state->viewportConstraints();
+}
+
+static inline CGPoint operator*(CGPoint& a, const CGSize& b)
+{
+ return CGPointMake(a.x * b.width, a.y * b.height);
+}
+
+void ScrollingTreeFixedNode::parentScrollPositionDidChange(const IntRect& viewportRect)
+{
+ FloatPoint layerPosition = m_constraints.layerPositionForViewportRect(viewportRect);
+
+ CGRect layerBounds = [m_layer.get() bounds];
+ CGPoint anchorPoint = [m_layer.get() anchorPoint];
+ CGPoint newPosition = layerPosition - m_constraints.alignmentOffset() + anchorPoint * layerBounds.size;
+ [m_layer.get() setPosition:newPosition];
+
+ if (!m_children)
+ return;
+
+ size_t size = m_children->size();
+ for (size_t i = 0; i < size; ++i)
+ m_children->at(i)->parentScrollPositionDidChange(viewportRect);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(THREADED_SCROLLING)
{
ASSERT(!shouldUpdateScrollLayerPositionOnMainThread());
m_scrollLayer.get().position = CGPointMake(-position.x() + scrollOrigin().x(), -position.y() + scrollOrigin().y());
+
+ if (!m_children)
+ return;
+
+ size_t size = m_children->size();
+ for (size_t i = 0; i < size; ++i)
+ m_children->at(i)->parentScrollPositionDidChange(IntRect(position, viewportRect().size()));
}
IntPoint ScrollingTreeScrollingNodeMac::minimumScrollPosition() const
if (!scrollingCoordinator)
return;
- ScrollingNodeType nodeType = ScrollingNode;
+ // FIXME: When we support overflow areas, we will have to refine this for overflow areas that are also
+ // positon:fixed.
+ ScrollingNodeType nodeType;
+ if (renderer()->style()->position() == FixedPosition)
+ nodeType = FixedNode;
+ else
+ nodeType = ScrollingNode;
+
ScrollingNodeID parentID = parent ? parent->scrollLayerID() : 0;
m_scrollLayerID = scrollingCoordinator->attachToStateTree(nodeType, scrollingCoordinator->uniqueScrollLayerID(), parentID);
}
GraphicsLayer* scrollingContentsLayer() const { return m_scrollingContentsLayer.get(); }
void attachToScrollingCoordinator(RenderLayerBacking* parent);
+ void detachFromScrollingCoordinator();
uint64_t scrollLayerID() const { return m_scrollLayerID; }
bool hasMaskLayer() const { return m_maskLayer != 0; }
bool requiresScrollCornerLayer() const;
bool updateScrollingLayers(bool scrollingLayers);
- void detachFromScrollingCoordinator();
-
GraphicsLayerPaintingPhase paintingPhaseForPrimaryLayer() const;
IntSize contentOffsetInCompostingLayer() const;
#include "RenderVideo.h"
#include "RenderView.h"
#include "ScrollbarTheme.h"
+#include "ScrollingConstraints.h"
#include "ScrollingCoordinator.h"
#include "Settings.h"
#include "TiledBacking.h"
ASSERT(m_flushingLayers);
m_flushingLayers = false;
+
+ if (!m_viewportConstrainedLayersNeedingUpdate.isEmpty()) {
+ HashSet<RenderLayer*>::const_iterator end = m_viewportConstrainedLayersNeedingUpdate.end();
+ for (HashSet<RenderLayer*>::const_iterator it = m_viewportConstrainedLayersNeedingUpdate.begin(); it != end; ++it)
+ registerOrUpdateViewportConstrainedLayer(*it);
+
+ m_viewportConstrainedLayersNeedingUpdate.clear();
+ }
}
-void RenderLayerCompositor::didFlushChangesForLayer(RenderLayer*)
+void RenderLayerCompositor::didFlushChangesForLayer(RenderLayer* layer)
{
+ if (m_viewportConstrainedLayers.contains(layer))
+ m_viewportConstrainedLayersNeedingUpdate.add(layer);
}
void RenderLayerCompositor::notifyFlushBeforeDisplayRefresh(const GraphicsLayer*)
layerChanged = true;
}
+
+ // Need to add for every compositing layer, because a composited layer may change from being non-fixed to fixed.
+ updateViewportConstraintStatus(layer);
} else {
if (layer->backing()) {
// If we're removing backing on a reflection, clear the source GraphicsLayer's pointer to
backing->graphicsLayer()->setReplicatedByLayer(0);
}
}
+
+ removeViewportConstrainedLayer(layer);
layer->clearBacking();
layerChanged = true;
if (!child->isComposited() || parent->renderer()->documentBeingDestroyed())
return;
+ removeViewportConstrainedLayer(child);
repaintInCompositedAncestor(child, child->backing()->compositedBounds());
setCompositingParent(child, 0);
if (!layer)
return;
- if (layer->isComposited())
+ if (layer->isComposited()) {
+ removeViewportConstrainedLayer(layer);
layer->clearBacking();
+ }
for (RenderLayer* currLayer = layer->firstChild(); currLayer; currLayer = currLayer->nextSibling())
clearBackingForLayerIncludingDescendants(currLayer);
rootLayer->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
}
+static bool isRootmostFixedOrStickyLayer(RenderLayer* layer)
+{
+ if (layer->renderer()->isStickyPositioned())
+ return true;
+
+ if (layer->renderer()->style()->position() != FixedPosition)
+ return false;
+
+ for (RenderLayer* stackingContext = layer->stackingContext(); stackingContext; stackingContext = stackingContext->stackingContext()) {
+ if (stackingContext->isComposited() && stackingContext->renderer()->style()->position() == FixedPosition)
+ return false;
+ }
+
+ return true;
+}
+
+void RenderLayerCompositor::updateViewportConstraintStatus(RenderLayer* layer)
+{
+ if (isRootmostFixedOrStickyLayer(layer))
+ addViewportConstrainedLayer(layer);
+ else
+ removeViewportConstrainedLayer(layer);
+}
+
+void RenderLayerCompositor::addViewportConstrainedLayer(RenderLayer* layer)
+{
+ m_viewportConstrainedLayers.add(layer);
+ registerOrUpdateViewportConstrainedLayer(layer);
+}
+
+void RenderLayerCompositor::removeViewportConstrainedLayer(RenderLayer* layer)
+{
+ if (!m_viewportConstrainedLayers.contains(layer))
+ return;
+
+ unregisterViewportConstrainedLayer(layer);
+ m_viewportConstrainedLayers.remove(layer);
+}
+
+const FixedPositionViewportConstraints RenderLayerCompositor::computeFixedViewportConstraints(RenderLayer* layer)
+{
+ ASSERT(layer->isComposited());
+
+ FrameView* frameView = m_renderView->frameView();
+ LayoutRect viewportRect = frameView->visibleContentRect();
+
+ FixedPositionViewportConstraints constraints = FixedPositionViewportConstraints();
+
+ GraphicsLayer* graphicsLayer = layer->backing()->graphicsLayer();
+
+ constraints.setLayerPositionAtLastLayout(graphicsLayer->position());
+ constraints.setViewportRectAtLastLayout(viewportRect);
+
+ RenderStyle* style = layer->renderer()->style();
+ if (!style->left().isAuto())
+ constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeLeft);
+
+ if (!style->right().isAuto())
+ constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeRight);
+
+ if (!style->top().isAuto())
+ constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeTop);
+
+ if (!style->bottom().isAuto())
+ constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeBottom);
+
+ // If left and right are auto, use left.
+ if (style->left().isAuto() && style->right().isAuto())
+ constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeLeft);
+
+ // If top and bottom are auto, use top.
+ if (style->top().isAuto() && style->bottom().isAuto())
+ constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeTop);
+
+ return constraints;
+}
+
+const StickyPositionViewportConstraints RenderLayerCompositor::computeStickyViewportConstraints(RenderLayer* layer)
+{
+ ASSERT(layer->isComposited());
+
+ FrameView* frameView = m_renderView->frameView();
+ LayoutRect viewportRect = frameView->visibleContentRect();
+
+ StickyPositionViewportConstraints constraints = StickyPositionViewportConstraints();
+
+ RenderBoxModelObject* renderer = toRenderBoxModelObject(layer->renderer());
+
+ renderer->computeStickyPositionConstraints(constraints, viewportRect);
+
+ GraphicsLayer* graphicsLayer = layer->backing()->graphicsLayer();
+
+ constraints.setLayerPositionAtLastLayout(graphicsLayer->position());
+ constraints.setStickyOffsetAtLastLayout(renderer->stickyPositionOffset());
+
+ return constraints;
+}
+
+static RenderLayerBacking* nearestScrollingCoordinatorAncestor(RenderLayer* layer)
+{
+ RenderLayer* ancestor = layer->parent();
+ while (ancestor) {
+ if (RenderLayerBacking* backing = ancestor->backing()) {
+ if (backing->scrollLayerID() && !ancestor->scrollsOverflow())
+ return backing;
+ }
+ ancestor = ancestor->parent();
+ }
+
+ return 0;
+}
+
+void RenderLayerCompositor::registerOrUpdateViewportConstrainedLayer(RenderLayer* layer)
+{
+ // FIXME: We should support sticky position here! And we should eventuall support fixed/sticky elements
+ // that are inside non-main frames once we get non-main frames scrolling with the ScrollingCoordinator.
+ if (layer->renderer()->isStickyPositioned() || m_renderView->document()->ownerElement())
+ return;
+
+ ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator();
+ if (!scrollingCoordinator)
+ return;
+
+ if (!scrollingCoordinator->supportsFixedPositionLayers() || !layer->parent())
+ return;
+
+ ASSERT(layer->renderer()->style()->position() == FixedPosition);
+ ASSERT(m_viewportConstrainedLayers.contains(layer));
+ ASSERT(layer->isComposited());
+
+ RenderLayerBacking* backing = layer->backing();
+ if (!backing)
+ return;
+
+ ScrollingNodeID nodeID = backing->scrollLayerID();
+ if (!nodeID) {
+ RenderLayerBacking* parent = nearestScrollingCoordinatorAncestor(layer);
+ if (!parent)
+ return;
+ backing->attachToScrollingCoordinator(parent);
+ nodeID = backing->scrollLayerID();
+ }
+
+ if (layer->renderer()->isStickyPositioned())
+ scrollingCoordinator->updateViewportConstrainedNode(nodeID, computeStickyViewportConstraints(layer), backing->graphicsLayer());
+ else
+ scrollingCoordinator->updateViewportConstrainedNode(nodeID, computeFixedViewportConstraints(layer), backing->graphicsLayer());
+}
+
+void RenderLayerCompositor::unregisterViewportConstrainedLayer(RenderLayer* layer)
+{
+ ASSERT(m_viewportConstrainedLayers.contains(layer));
+
+ if (RenderLayerBacking* backing = layer->backing())
+ backing->detachFromScrollingCoordinator();
+}
+
void RenderLayerCompositor::windowScreenDidChange(PlatformDisplayID displayID)
{
if (m_layerUpdater)
namespace WebCore {
+class FixedPositionViewportConstraints;
class GraphicsLayer;
class GraphicsLayerUpdater;
class RenderEmbeddedObject;
class RenderPart;
class ScrollingCoordinator;
+class StickyPositionViewportConstraints;
#if ENABLE(VIDEO)
class RenderVideo;
#endif
void documentBackgroundColorDidChange();
+ void updateViewportConstraintStatus(RenderLayer*);
+ void removeViewportConstrainedLayer(RenderLayer*);
+
void resetTrackedRepaintRects();
void setTracksRepaints(bool);
bool requiresCompositingForOverflowScrolling(const RenderLayer*) const;
bool requiresCompositingForIndirectReason(RenderObject*, bool hasCompositedDescendants, bool has3DTransformedDescendants, RenderLayer::IndirectCompositingReason&) const;
+ void addViewportConstrainedLayer(RenderLayer*);
+ void registerOrUpdateViewportConstrainedLayer(RenderLayer*);
+ void unregisterViewportConstrainedLayer(RenderLayer*);
+
+ const FixedPositionViewportConstraints computeFixedViewportConstraints(RenderLayer*);
+ const StickyPositionViewportConstraints computeStickyViewportConstraints(RenderLayer*);
+
bool requiresScrollLayer(RootLayerAttachment) const;
bool requiresHorizontalScrollbarLayer() const;
bool requiresVerticalScrollbarLayer() const;
OwnPtr<GraphicsLayer> m_clipLayer;
OwnPtr<GraphicsLayer> m_scrollLayer;
+ HashSet<RenderLayer*> m_viewportConstrainedLayers;
+ HashSet<RenderLayer*> m_viewportConstrainedLayersNeedingUpdate;
+
// Enclosing layer for overflow controls and the clipping layer
OwnPtr<GraphicsLayer> m_overflowControlsHostLayer;