summaryrefslogtreecommitdiff
path: root/Source/WebCore/page/scrolling
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/page/scrolling')
-rw-r--r--Source/WebCore/page/scrolling/ScrollingCoordinator.cpp252
-rw-r--r--Source/WebCore/page/scrolling/ScrollingCoordinator.h62
-rw-r--r--Source/WebCore/page/scrolling/ScrollingCoordinatorNone.cpp77
-rw-r--r--Source/WebCore/page/scrolling/ScrollingThread.cpp7
-rw-r--r--Source/WebCore/page/scrolling/ScrollingThread.h2
-rw-r--r--Source/WebCore/page/scrolling/ScrollingTree.cpp95
-rw-r--r--Source/WebCore/page/scrolling/ScrollingTree.h28
-rw-r--r--Source/WebCore/page/scrolling/ScrollingTreeNode.cpp20
-rw-r--r--Source/WebCore/page/scrolling/ScrollingTreeNode.h19
-rw-r--r--Source/WebCore/page/scrolling/ScrollingTreeState.cpp50
-rw-r--r--Source/WebCore/page/scrolling/ScrollingTreeState.h31
-rw-r--r--Source/WebCore/page/scrolling/chromium/ScrollingCoordinatorChromium.cpp99
-rw-r--r--Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm26
-rw-r--r--Source/WebCore/page/scrolling/mac/ScrollingTreeNodeMac.h31
-rw-r--r--Source/WebCore/page/scrolling/mac/ScrollingTreeNodeMac.mm197
15 files changed, 917 insertions, 79 deletions
diff --git a/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp b/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp
index e569b2c25..5c14d995d 100644
--- a/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp
+++ b/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp
@@ -25,8 +25,6 @@
#include "config.h"
-#if ENABLE(THREADED_SCROLLING)
-
#include "ScrollingCoordinator.h"
#include "Frame.h"
@@ -35,49 +33,54 @@
#include "Page.h"
#include "PlatformWheelEvent.h"
#include "Region.h"
+#include "RenderView.h"
#include "ScrollAnimator.h"
+#include "ScrollingTreeState.h"
+#include <wtf/MainThread.h>
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "RenderLayerCompositor.h"
+#endif
+
+#if ENABLE(THREADED_SCROLLING)
#include "ScrollingThread.h"
#include "ScrollingTree.h"
-#include "ScrollingTreeState.h"
#include <wtf/Functional.h>
-#include <wtf/MainThread.h>
#include <wtf/PassRefPtr.h>
+#endif
namespace WebCore {
-PassRefPtr<ScrollingCoordinator> ScrollingCoordinator::create(Page* page)
-{
- return adoptRef(new ScrollingCoordinator(page));
-}
-
ScrollingCoordinator::ScrollingCoordinator(Page* page)
: m_page(page)
- , m_scrollingTree(ScrollingTree::create(this))
+#if ENABLE(THREADED_SCROLLING)
, m_scrollingTreeState(ScrollingTreeState::create())
+ , m_scrollingTree(ScrollingTree::create(this))
, m_scrollingTreeStateCommitterTimer(this, &ScrollingCoordinator::scrollingTreeStateCommitterTimerFired)
+#endif
{
}
-ScrollingCoordinator::~ScrollingCoordinator()
-{
- ASSERT(!m_page);
- ASSERT(!m_scrollingTree);
-}
-
void ScrollingCoordinator::pageDestroyed()
{
ASSERT(m_page);
m_page = 0;
+#if ENABLE(THREADED_SCROLLING)
+ m_scrollingTreeStateCommitterTimer.stop();
+
// Invalidating the scrolling tree will break the reference cycle between the ScrollingCoordinator and ScrollingTree objects.
ScrollingThread::dispatch(bind(&ScrollingTree::invalidate, m_scrollingTree.release()));
+#endif
}
+#if ENABLE(THREADED_SCROLLING)
ScrollingTree* ScrollingCoordinator::scrollingTree() const
{
ASSERT(m_scrollingTree);
return m_scrollingTree.get();
}
+#endif
bool ScrollingCoordinator::coordinatesScrollingForFrameView(FrameView* frameView) const
{
@@ -88,37 +91,66 @@ bool ScrollingCoordinator::coordinatesScrollingForFrameView(FrameView* frameView
if (frameView->frame() != m_page->mainFrame())
return false;
- return true;
+ // We currently only support composited mode.
+#if USE(ACCELERATED_COMPOSITING)
+ RenderView* renderView = m_page->mainFrame()->contentRenderer();
+ if (!renderView)
+ return false;
+ return renderView->usesCompositing();
+#else
+ return false;
+#endif
}
-void ScrollingCoordinator::frameViewLayoutUpdated(FrameView* frameView)
+static Region computeNonFastScrollableRegion(FrameView* frameView)
{
- ASSERT(isMainThread());
- ASSERT(m_page);
+ Region nonFastScrollableRegion;
- if (!coordinatesScrollingForFrameView(frameView))
- return;
+ HashSet<FrameView*> childFrameViews;
+ for (HashSet<RefPtr<Widget> >::const_iterator it = frameView->children()->begin(), end = frameView->children()->end(); it != end; ++it) {
+ if ((*it)->isFrameView())
+ childFrameViews.add(static_cast<FrameView*>(it->get()));
+ }
- // Compute the region of the page that we can't do fast scrolling for. This currently includes
- // all scrollable areas, such as subframes, overflow divs and list boxes.
- Region nonScrollableRegion;
if (const FrameView::ScrollableAreaSet* scrollableAreas = frameView->scrollableAreas()) {
for (FrameView::ScrollableAreaSet::const_iterator it = scrollableAreas->begin(), end = scrollableAreas->end(); it != end; ++it) {
ScrollableArea* scrollableArea = *it;
// Check if this area can be scrolled at all.
+ // If this scrollable area is a frame view that itself has scrollable areas, then we need to add it to the region.
if ((!scrollableArea->horizontalScrollbar() || !scrollableArea->horizontalScrollbar()->enabled())
- && (!scrollableArea->verticalScrollbar() || !scrollableArea->verticalScrollbar()->enabled()))
- continue;
+ && (!scrollableArea->verticalScrollbar() || !scrollableArea->verticalScrollbar()->enabled())
+ && (!childFrameViews.contains(static_cast<FrameView*>(scrollableArea)) || !static_cast<FrameView*>(scrollableArea)->scrollableAreas()))
+ continue;
- nonScrollableRegion.unite(scrollableArea->scrollableAreaBoundingBox());
+ nonFastScrollableRegion.unite(scrollableArea->scrollableAreaBoundingBox());
}
}
- m_scrollingTreeState->setViewportRect(IntRect(IntPoint(), frameView->visibleContentRect().size()));
- m_scrollingTreeState->setContentsSize(frameView->contentsSize());
- m_scrollingTreeState->setNonFastScrollableRegion(nonScrollableRegion);
- scheduleTreeStateCommit();
+ return nonFastScrollableRegion;
+}
+
+void ScrollingCoordinator::frameViewLayoutUpdated(FrameView* frameView)
+{
+ ASSERT(isMainThread());
+ ASSERT(m_page);
+
+ // Compute the region of the page that we can't do fast scrolling for. This currently includes
+ // all scrollable areas, such as subframes, overflow divs and list boxes. We need to do this even if the
+ // frame view whose layout was updated is not the main frame.
+ Region nonFastScrollableRegion = computeNonFastScrollableRegion(m_page->mainFrame()->view());
+ setNonFastScrollableRegion(nonFastScrollableRegion);
+
+ if (!coordinatesScrollingForFrameView(frameView))
+ return;
+
+ setScrollParameters(frameView->horizontalScrollElasticity(),
+ frameView->verticalScrollElasticity(),
+ frameView->horizontalScrollbar() && frameView->horizontalScrollbar()->enabled(),
+ frameView->verticalScrollbar() && frameView->verticalScrollbar()->enabled(),
+ IntRect(IntPoint(), frameView->visibleContentRect().size()),
+ frameView->contentsSize());
+
}
void ScrollingCoordinator::frameViewWheelEventHandlerCountChanged(FrameView*)
@@ -129,6 +161,91 @@ void ScrollingCoordinator::frameViewWheelEventHandlerCountChanged(FrameView*)
recomputeWheelEventHandlerCount();
}
+void ScrollingCoordinator::frameViewHasSlowRepaintObjectsDidChange(FrameView* frameView)
+{
+ ASSERT(isMainThread());
+ ASSERT(m_page);
+
+ if (!coordinatesScrollingForFrameView(frameView))
+ return;
+
+ updateShouldUpdateScrollLayerPositionOnMainThread();
+}
+
+void ScrollingCoordinator::frameViewHasFixedObjectsDidChange(FrameView* frameView)
+{
+ ASSERT(isMainThread());
+ ASSERT(m_page);
+
+ if (!coordinatesScrollingForFrameView(frameView))
+ return;
+
+ updateShouldUpdateScrollLayerPositionOnMainThread();
+}
+
+static GraphicsLayer* scrollLayerForFrameView(FrameView* frameView)
+{
+#if USE(ACCELERATED_COMPOSITING)
+ Frame* frame = frameView->frame();
+ if (!frame)
+ return 0;
+
+ RenderView* renderView = frame->contentRenderer();
+ if (!renderView)
+ return 0;
+ return renderView->compositor()->scrollLayer();
+#else
+ return 0;
+#endif
+}
+
+void ScrollingCoordinator::frameViewRootLayerDidChange(FrameView* frameView)
+{
+ ASSERT(isMainThread());
+ ASSERT(m_page);
+
+ if (frameView->frame() != m_page->mainFrame())
+ return;
+
+ frameViewLayoutUpdated(frameView);
+ recomputeWheelEventHandlerCount();
+ updateShouldUpdateScrollLayerPositionOnMainThread();
+ setScrollLayer(scrollLayerForFrameView(frameView));
+}
+
+bool ScrollingCoordinator::requestScrollPositionUpdate(FrameView* frameView, const IntPoint& scrollPosition)
+{
+ ASSERT(isMainThread());
+ ASSERT(m_page);
+
+ if (!coordinatesScrollingForFrameView(frameView))
+ return false;
+
+#if ENABLE(THREADED_SCROLLING)
+ ScrollingThread::dispatch(bind(&ScrollingTree::setMainFrameScrollPosition, m_scrollingTree.get(), scrollPosition));
+ return true;
+#else
+ UNUSED_PARAM(scrollPosition);
+ return false;
+#endif
+}
+
+bool ScrollingCoordinator::handleWheelEvent(FrameView*, const PlatformWheelEvent& wheelEvent)
+{
+ ASSERT(isMainThread());
+ ASSERT(m_page);
+
+#if ENABLE(THREADED_SCROLLING)
+ if (m_scrollingTree->willWheelEventStartSwipeGesture(wheelEvent))
+ return false;
+
+ ScrollingThread::dispatch(bind(&ScrollingTree::handleWheelEvent, m_scrollingTree.get(), wheelEvent));
+#else
+ UNUSED_PARAM(wheelEvent);
+#endif
+ return true;
+}
+
void ScrollingCoordinator::updateMainFrameScrollPosition(const IntPoint& scrollPosition)
{
ASSERT(isMainThread());
@@ -141,8 +258,25 @@ void ScrollingCoordinator::updateMainFrameScrollPosition(const IntPoint& scrollP
return;
frameView->setConstrainsScrollingToContentEdge(false);
- frameView->scrollToOffsetWithoutAnimation(scrollPosition);
+ frameView->notifyScrollPositionChanged(scrollPosition);
+ frameView->setConstrainsScrollingToContentEdge(true);
+}
+
+void ScrollingCoordinator::updateMainFrameScrollPositionAndScrollLayerPosition(const IntPoint& scrollPosition)
+{
+#if USE(ACCELERATED_COMPOSITING)
+ FrameView* frameView = m_page->mainFrame()->view();
+
+ // Make sure to update the main frame scroll position before changing the scroll layer position,
+ // otherwise we'll introduce jittering on pages with slow repaint objects (like background-attachment: fixed).
+ frameView->updateCompositingLayers();
+ frameView->setConstrainsScrollingToContentEdge(false);
+ frameView->notifyScrollPositionChanged(scrollPosition);
frameView->setConstrainsScrollingToContentEdge(true);
+
+ if (GraphicsLayer* scrollLayer = scrollLayerForFrameView(frameView))
+ scrollLayer->setPosition(-frameView->scrollPosition());
+#endif
}
void ScrollingCoordinator::recomputeWheelEventHandlerCount()
@@ -152,11 +286,60 @@ void ScrollingCoordinator::recomputeWheelEventHandlerCount()
if (frame->document())
wheelEventHandlerCount += frame->document()->wheelEventHandlerCount();
}
+ setWheelEventHandlerCount(wheelEventHandlerCount);
+}
+
+void ScrollingCoordinator::updateShouldUpdateScrollLayerPositionOnMainThread()
+{
+ FrameView* frameView = m_page->mainFrame()->view();
+
+ // FIXME: Having fixed objects on the page should not trigger the slow path.
+ setShouldUpdateScrollLayerPositionOnMainThread(frameView->hasSlowRepaintObjects() || frameView->hasFixedObjects());
+}
+
+#if ENABLE(THREADED_SCROLLING)
+void ScrollingCoordinator::setScrollLayer(GraphicsLayer* scrollLayer)
+{
+ m_scrollingTreeState->setScrollLayer(scrollLayer);
+ scheduleTreeStateCommit();
+}
+void ScrollingCoordinator::setNonFastScrollableRegion(const Region& region)
+{
+ m_scrollingTreeState->setNonFastScrollableRegion(region);
+ scheduleTreeStateCommit();
+}
+
+void ScrollingCoordinator::setScrollParameters(ScrollElasticity horizontalScrollElasticity,
+ ScrollElasticity verticalScrollElasticity,
+ bool hasEnabledHorizontalScrollbar,
+ bool hasEnabledVerticalScrollbar,
+ const IntRect& viewportRect,
+ const IntSize& contentsSize)
+{
+ m_scrollingTreeState->setHorizontalScrollElasticity(horizontalScrollElasticity);
+ m_scrollingTreeState->setVerticalScrollElasticity(verticalScrollElasticity);
+ m_scrollingTreeState->setHasEnabledHorizontalScrollbar(hasEnabledHorizontalScrollbar);
+ m_scrollingTreeState->setHasEnabledVerticalScrollbar(hasEnabledVerticalScrollbar);
+
+ m_scrollingTreeState->setViewportRect(viewportRect);
+ m_scrollingTreeState->setContentsSize(contentsSize);
+ scheduleTreeStateCommit();
+}
+
+
+void ScrollingCoordinator::setWheelEventHandlerCount(unsigned wheelEventHandlerCount)
+{
m_scrollingTreeState->setWheelEventHandlerCount(wheelEventHandlerCount);
scheduleTreeStateCommit();
}
+void ScrollingCoordinator::setShouldUpdateScrollLayerPositionOnMainThread(bool shouldUpdateScrollLayerPositionOnMainThread)
+{
+ m_scrollingTreeState->setShouldUpdateScrollLayerPositionOnMainThread(shouldUpdateScrollLayerPositionOnMainThread);
+ scheduleTreeStateCommit();
+}
+
void ScrollingCoordinator::scheduleTreeStateCommit()
{
if (m_scrollingTreeStateCommitterTimer.isActive())
@@ -189,7 +372,6 @@ void ScrollingCoordinator::commitTreeState()
OwnPtr<ScrollingTreeState> treeState = m_scrollingTreeState->commit();
ScrollingThread::dispatch(bind(&ScrollingTree::commitNewTreeState, m_scrollingTree.get(), treeState.release()));
}
+#endif
} // namespace WebCore
-
-#endif // ENABLE(THREADED_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/ScrollingCoordinator.h b/Source/WebCore/page/scrolling/ScrollingCoordinator.h
index eb597b8b0..00b289fe2 100644
--- a/Source/WebCore/page/scrolling/ScrollingCoordinator.h
+++ b/Source/WebCore/page/scrolling/ScrollingCoordinator.h
@@ -26,14 +26,16 @@
#ifndef ScrollingCoordinator_h
#define ScrollingCoordinator_h
-#if ENABLE(THREADED_SCROLLING)
-
#include "GraphicsLayer.h"
#include "IntRect.h"
+#include "ScrollTypes.h"
#include "Timer.h"
#include <wtf/Forward.h>
+
+#if ENABLE(THREADED_SCROLLING)
#include <wtf/ThreadSafeRefCounted.h>
#include <wtf/Threading.h>
+#endif
#if PLATFORM(MAC)
#include <wtf/RetainPtr.h>
@@ -45,11 +47,12 @@ class FrameView;
class GraphicsLayer;
class Page;
class PlatformWheelEvent;
-class ScrollingTree;
+class Region;
+class ScrollingCoordinatorPrivate;
class ScrollingTreeState;
-#if ENABLE(GESTURE_EVENTS)
-class PlatformGestureEvent;
+#if ENABLE(THREADED_SCROLLING)
+class ScrollingTree;
#endif
class ScrollingCoordinator : public ThreadSafeRefCounted<ScrollingCoordinator> {
@@ -59,7 +62,9 @@ public:
void pageDestroyed();
+#if ENABLE(THREADED_SCROLLING)
ScrollingTree* scrollingTree() const;
+#endif
// Return whether this scrolling coordinator handles scrolling for the given frame view.
bool coordinatesScrollingForFrameView(FrameView*) const;
@@ -71,37 +76,68 @@ public:
// frame view's underlying document.
void frameViewWheelEventHandlerCountChanged(FrameView*);
- // Should be called whenever the scroll layer for the given frame view changes.
- void frameViewScrollLayerDidChange(FrameView*, const GraphicsLayer*);
+ // Should be called whenever the slow repaint objects counter changes between zero and one.
+ void frameViewHasSlowRepaintObjectsDidChange(FrameView*);
+
+ // Should be called whenever the fixed objects counter changes between zero and one.
+ // FIXME: This is a temporary workaround so that we'll fall into main thread scrolling mode
+ // if a page has fixed elements. The scrolling tree should know about the fixed elements
+ // so it can make sure they stay fixed even when we scroll on the scrolling thread.
+ void frameViewHasFixedObjectsDidChange(FrameView*);
+
+ // Should be called whenever the root layer for the given frame view changes.
+ void frameViewRootLayerDidChange(FrameView*);
// Should be called whenever the horizontal scrollbar layer for the given frame view changes.
void frameViewHorizontalScrollbarLayerDidChange(FrameView*, GraphicsLayer* horizontalScrollbarLayer);
- // Should be called whenever the horizontal scrollbar layer for the given frame view changes.
+ // Should be called whenever the vertical scrollbar layer for the given frame view changes.
void frameViewVerticalScrollbarLayerDidChange(FrameView*, GraphicsLayer* verticalScrollbarLayer);
+ // Requests that the scrolling coordinator updates the scroll position of the given frame view. If this function returns true, it means that the
+ // position will be updated asynchronously. If it returns false, the caller should update the scrolling position itself.
+ bool requestScrollPositionUpdate(FrameView*, const IntPoint&);
+
+ // Handle the wheel event on the scrolling thread. Returns whether the event was handled or not.
+ bool handleWheelEvent(FrameView*, const PlatformWheelEvent&);
+
// Dispatched by the scrolling tree whenever the main frame scroll position changes.
void updateMainFrameScrollPosition(const IntPoint&);
+ // Dispatched by the scrolling tree whenever the main frame scroll position changes and the scroll layer position needs to be updated as well.
+ void updateMainFrameScrollPositionAndScrollLayerPosition(const IntPoint&);
+
private:
explicit ScrollingCoordinator(Page*);
void recomputeWheelEventHandlerCount();
+ void updateShouldUpdateScrollLayerPositionOnMainThread();
+ void setScrollLayer(GraphicsLayer*);
+ void setNonFastScrollableRegion(const Region&);
+ void setScrollParameters(ScrollElasticity horizontalScrollElasticity, ScrollElasticity verticalScrollElasticity,
+ bool hasEnabledHorizontalScrollbar, bool hasEnabledVerticalScrollbar,
+ const IntRect& viewportRect, const IntSize& contentsSize);
+ void setWheelEventHandlerCount(unsigned);
+ void setShouldUpdateScrollLayerPositionOnMainThread(bool);
+
+ Page* m_page;
+
+#if ENABLE(THREADED_SCROLLING)
void scheduleTreeStateCommit();
+
void scrollingTreeStateCommitterTimerFired(Timer<ScrollingCoordinator>*);
void commitTreeStateIfNeeded();
void commitTreeState();
- Page* m_page;
- RefPtr<ScrollingTree> m_scrollingTree;
-
OwnPtr<ScrollingTreeState> m_scrollingTreeState;
+ RefPtr<ScrollingTree> m_scrollingTree;
Timer<ScrollingCoordinator> m_scrollingTreeStateCommitterTimer;
+#endif
+
+ ScrollingCoordinatorPrivate* m_private;
};
} // namespace WebCore
-#endif // ENABLE(THREADED_SCROLLING)
-
#endif // ScrollingCoordinator_h
diff --git a/Source/WebCore/page/scrolling/ScrollingCoordinatorNone.cpp b/Source/WebCore/page/scrolling/ScrollingCoordinatorNone.cpp
new file mode 100644
index 000000000..d06d6bb34
--- /dev/null
+++ b/Source/WebCore/page/scrolling/ScrollingCoordinatorNone.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2012 Google 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 "ScrollingCoordinator.h"
+
+namespace WebCore {
+
+class ScrollingCoordinatorPrivate {
+};
+
+#if !ENABLE(THREADED_SCROLLING)
+PassRefPtr<ScrollingCoordinator> ScrollingCoordinator::create(Page* page)
+{
+ return adoptRef(new ScrollingCoordinator(page));
+}
+
+ScrollingCoordinator::~ScrollingCoordinator()
+{
+ ASSERT(!m_page);
+}
+
+void ScrollingCoordinator::frameViewHorizontalScrollbarLayerDidChange(FrameView*, GraphicsLayer*)
+{
+}
+
+void ScrollingCoordinator::frameViewVerticalScrollbarLayerDidChange(FrameView*, GraphicsLayer*)
+{
+}
+
+void ScrollingCoordinator::setScrollLayer(GraphicsLayer*)
+{
+}
+
+void ScrollingCoordinator::setNonFastScrollableRegion(const Region&)
+{
+}
+
+void ScrollingCoordinator::setScrollParameters(ScrollElasticity, ScrollElasticity, bool, bool, const IntRect&, const IntSize&)
+{
+}
+
+void ScrollingCoordinator::setWheelEventHandlerCount(unsigned)
+{
+}
+
+void ScrollingCoordinator::setShouldUpdateScrollLayerPositionOnMainThread(bool)
+{
+}
+
+#endif // !ENABLE(THREADED_SCROLLING)
+
+}
+
diff --git a/Source/WebCore/page/scrolling/ScrollingThread.cpp b/Source/WebCore/page/scrolling/ScrollingThread.cpp
index fc5a405da..f92969cc5 100644
--- a/Source/WebCore/page/scrolling/ScrollingThread.cpp
+++ b/Source/WebCore/page/scrolling/ScrollingThread.cpp
@@ -71,17 +71,16 @@ void ScrollingThread::createThreadIfNeeded()
// Wait for the thread to initialize the run loop.
{
MutexLocker locker(m_initializeRunLoopConditionMutex);
-
+#if PLATFORM(MAC)
while (!m_threadRunLoop)
m_initializeRunLoopCondition.wait(m_initializeRunLoopConditionMutex);
+#endif
}
}
-void* ScrollingThread::threadCallback(void* scrollingThread)
+void ScrollingThread::threadCallback(void* scrollingThread)
{
static_cast<ScrollingThread*>(scrollingThread)->threadBody();
-
- return 0;
}
void ScrollingThread::threadBody()
diff --git a/Source/WebCore/page/scrolling/ScrollingThread.h b/Source/WebCore/page/scrolling/ScrollingThread.h
index 22671e4f5..d8dfa2de0 100644
--- a/Source/WebCore/page/scrolling/ScrollingThread.h
+++ b/Source/WebCore/page/scrolling/ScrollingThread.h
@@ -52,7 +52,7 @@ private:
static ScrollingThread& shared();
void createThreadIfNeeded();
- static void* threadCallback(void* scrollingThread);
+ static void threadCallback(void* scrollingThread);
void threadBody();
void dispatchFunctionsFromScrollingThread();
diff --git a/Source/WebCore/page/scrolling/ScrollingTree.cpp b/Source/WebCore/page/scrolling/ScrollingTree.cpp
index bc1c50d9f..d58c62bd3 100644
--- a/Source/WebCore/page/scrolling/ScrollingTree.cpp
+++ b/Source/WebCore/page/scrolling/ScrollingTree.cpp
@@ -46,6 +46,10 @@ ScrollingTree::ScrollingTree(ScrollingCoordinator* scrollingCoordinator)
: m_scrollingCoordinator(scrollingCoordinator)
, m_rootNode(ScrollingTreeNode::create(this))
, m_hasWheelEventHandlers(false)
+ , m_canGoBack(false)
+ , m_canGoForward(false)
+ , m_mainFramePinnedToTheLeft(false)
+ , m_mainFramePinnedToTheRight(false)
{
}
@@ -54,25 +58,36 @@ ScrollingTree::~ScrollingTree()
ASSERT(!m_scrollingCoordinator);
}
-bool ScrollingTree::tryToHandleWheelEvent(const PlatformWheelEvent& wheelEvent)
+ScrollingTree::EventResult ScrollingTree::tryToHandleWheelEvent(const PlatformWheelEvent& wheelEvent)
{
{
MutexLocker lock(m_mutex);
if (m_hasWheelEventHandlers)
- return false;
+ return SendToMainThread;
if (!m_nonFastScrollableRegion.isEmpty()) {
// FIXME: This is not correct for non-default scroll origins.
IntPoint position = wheelEvent.position();
position.moveBy(m_mainFrameScrollPosition);
if (m_nonFastScrollableRegion.contains(position))
- return false;
+ return SendToMainThread;
}
}
+ if (willWheelEventStartSwipeGesture(wheelEvent))
+ return DidNotHandleEvent;
+
ScrollingThread::dispatch(bind(&ScrollingTree::handleWheelEvent, this, wheelEvent));
- return true;
+ return DidHandleEvent;
+}
+
+void ScrollingTree::updateBackForwardState(bool canGoBack, bool canGoForward)
+{
+ MutexLocker locker(m_swipeStateMutex);
+
+ m_canGoBack = canGoBack;
+ m_canGoForward = canGoForward;
}
void ScrollingTree::handleWheelEvent(const PlatformWheelEvent& wheelEvent)
@@ -82,13 +97,31 @@ void ScrollingTree::handleWheelEvent(const PlatformWheelEvent& wheelEvent)
m_rootNode->handleWheelEvent(wheelEvent);
}
+void ScrollingTree::setMainFrameScrollPosition(const IntPoint& scrollPosition)
+{
+ ASSERT(ScrollingThread::isCurrentThread());
+
+ m_rootNode->setScrollPosition(scrollPosition);
+}
+
+static void derefScrollingCoordinator(ScrollingCoordinator* scrollingCoordinator)
+{
+ ASSERT(isMainThread());
+
+ scrollingCoordinator->deref();
+}
+
void ScrollingTree::invalidate()
{
// Invalidate is dispatched by the ScrollingCoordinator class on the ScrollingThread
// to break the reference cycle between ScrollingTree and ScrollingCoordinator when the
// ScrollingCoordinator's page is destroyed.
ASSERT(ScrollingThread::isCurrentThread());
- m_scrollingCoordinator = nullptr;
+
+ // Since this can potentially be the last reference to the scrolling coordinator,
+ // we need to release it on the main thread since it has member variables (such as timers)
+ // that expect to be destroyed from the main thread.
+ callOnMainThread(bind(derefScrollingCoordinator, m_scrollingCoordinator.release().leakRef()));
}
void ScrollingTree::commitNewTreeState(PassOwnPtr<ScrollingTreeState> scrollingTreeState)
@@ -107,6 +140,14 @@ void ScrollingTree::commitNewTreeState(PassOwnPtr<ScrollingTreeState> scrollingT
m_rootNode->update(scrollingTreeState.get());
}
+void ScrollingTree::setMainFramePinState(bool pinnedToTheLeft, bool pinnedToTheRight)
+{
+ MutexLocker locker(m_swipeStateMutex);
+
+ m_mainFramePinnedToTheLeft = pinnedToTheLeft;
+ m_mainFramePinnedToTheRight = pinnedToTheRight;
+}
+
void ScrollingTree::updateMainFrameScrollPosition(const IntPoint& scrollPosition)
{
if (!m_scrollingCoordinator)
@@ -120,6 +161,50 @@ void ScrollingTree::updateMainFrameScrollPosition(const IntPoint& scrollPosition
callOnMainThread(bind(&ScrollingCoordinator::updateMainFrameScrollPosition, m_scrollingCoordinator.get(), scrollPosition));
}
+void ScrollingTree::updateMainFrameScrollPositionAndScrollLayerPosition(const IntPoint& scrollPosition)
+{
+ if (!m_scrollingCoordinator)
+ return;
+
+ {
+ MutexLocker lock(m_mutex);
+ m_mainFrameScrollPosition = scrollPosition;
+ }
+
+ callOnMainThread(bind(&ScrollingCoordinator::updateMainFrameScrollPositionAndScrollLayerPosition, m_scrollingCoordinator.get(), scrollPosition));
+}
+
+bool ScrollingTree::canGoBack()
+{
+ MutexLocker lock(m_swipeStateMutex);
+
+ return m_canGoBack;
+}
+
+bool ScrollingTree::canGoForward()
+{
+ MutexLocker lock(m_swipeStateMutex);
+
+ return m_canGoForward;
+}
+
+bool ScrollingTree::willWheelEventStartSwipeGesture(const PlatformWheelEvent& wheelEvent)
+{
+ if (wheelEvent.phase() != PlatformWheelEventPhaseBegan)
+ return false;
+ if (!wheelEvent.deltaX())
+ return false;
+
+ MutexLocker lock(m_swipeStateMutex);
+
+ if (wheelEvent.deltaX() > 0 && m_mainFramePinnedToTheLeft && m_canGoBack)
+ return true;
+ if (wheelEvent.deltaX() < 0 && m_mainFramePinnedToTheRight && m_canGoForward)
+ return true;
+
+ return false;
+}
+
} // namespace WebCore
#endif // ENABLE(THREADED_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/ScrollingTree.h b/Source/WebCore/page/scrolling/ScrollingTree.h
index 76cbfda0a..00d2584c0 100644
--- a/Source/WebCore/page/scrolling/ScrollingTree.h
+++ b/Source/WebCore/page/scrolling/ScrollingTree.h
@@ -29,6 +29,7 @@
#if ENABLE(THREADED_SCROLLING)
#include "Region.h"
+#include <wtf/Functional.h>
#include <wtf/OwnPtr.h>
#include <wtf/PassOwnPtr.h>
#include <wtf/PassRefPtr.h>
@@ -52,18 +53,37 @@ public:
static PassRefPtr<ScrollingTree> create(ScrollingCoordinator*);
~ScrollingTree();
+ enum EventResult {
+ DidNotHandleEvent,
+ DidHandleEvent,
+ SendToMainThread
+ };
+
// Can be called from any thread. Will try to handle the wheel event on the scrolling thread.
// Returns true if the wheel event can be handled on the scrolling thread and false if the
// event must be sent again to the WebCore event handler.
- bool tryToHandleWheelEvent(const PlatformWheelEvent&);
+ EventResult tryToHandleWheelEvent(const PlatformWheelEvent&);
+
+ // Can be called from any thread. Will update the back forward state of the page, used for rubber-banding.
+ void updateBackForwardState(bool canGoBack, bool canGoForward);
// Must be called from the scrolling thread. Handles the wheel event.
void handleWheelEvent(const PlatformWheelEvent&);
+ void setMainFrameScrollPosition(const IntPoint&);
+
void invalidate();
void commitNewTreeState(PassOwnPtr<ScrollingTreeState>);
+ void setMainFramePinState(bool pinnedToTheLeft, bool pinnedToTheRight);
+
void updateMainFrameScrollPosition(const IntPoint& scrollPosition);
+ void updateMainFrameScrollPositionAndScrollLayerPosition(const IntPoint& scrollPosition);
+
+ bool canGoBack();
+ bool canGoForward();
+
+ bool willWheelEventStartSwipeGesture(const PlatformWheelEvent&);
private:
explicit ScrollingTree(ScrollingCoordinator*);
@@ -75,6 +95,12 @@ private:
Region m_nonFastScrollableRegion;
IntPoint m_mainFrameScrollPosition;
bool m_hasWheelEventHandlers;
+
+ Mutex m_swipeStateMutex;
+ bool m_canGoBack;
+ bool m_canGoForward;
+ bool m_mainFramePinnedToTheLeft;
+ bool m_mainFramePinnedToTheRight;
};
} // namespace WebCore
diff --git a/Source/WebCore/page/scrolling/ScrollingTreeNode.cpp b/Source/WebCore/page/scrolling/ScrollingTreeNode.cpp
index bd94f00dc..8626b89ff 100644
--- a/Source/WebCore/page/scrolling/ScrollingTreeNode.cpp
+++ b/Source/WebCore/page/scrolling/ScrollingTreeNode.cpp
@@ -34,6 +34,11 @@ namespace WebCore {
ScrollingTreeNode::ScrollingTreeNode(ScrollingTree* scrollingTree)
: m_scrollingTree(scrollingTree)
+ , m_shouldUpdateScrollLayerPositionOnMainThread(false)
+ , m_horizontalScrollElasticity(ScrollElasticityNone)
+ , m_verticalScrollElasticity(ScrollElasticityNone)
+ , m_hasEnabledHorizontalScrollbar(false)
+ , m_hasEnabledVerticalScrollbar(false)
{
}
@@ -48,6 +53,21 @@ void ScrollingTreeNode::update(ScrollingTreeState* state)
if (state->changedProperties() & ScrollingTreeState::ContentsSize)
m_contentsSize = state->contentsSize();
+
+ if (state->changedProperties() & ScrollingTreeState::ShouldUpdateScrollLayerPositionOnMainThread)
+ m_shouldUpdateScrollLayerPositionOnMainThread = state->shouldUpdateScrollLayerPositionOnMainThread();
+
+ if (state->changedProperties() & ScrollingTreeState::HorizontalScrollElasticity)
+ m_horizontalScrollElasticity = state->horizontalScrollElasticity();
+
+ if (state->changedProperties() & ScrollingTreeState::VerticalScrollElasticity)
+ m_verticalScrollElasticity = state->verticalScrollElasticity();
+
+ if (state->changedProperties() & ScrollingTreeState::HasEnabledHorizontalScrollbar)
+ m_hasEnabledHorizontalScrollbar = state->hasEnabledHorizontalScrollbar();
+
+ if (state->changedProperties() & ScrollingTreeState::HasEnabledVerticalScrollbar)
+ m_hasEnabledVerticalScrollbar = state->hasEnabledVerticalScrollbar();
}
} // namespace WebCore
diff --git a/Source/WebCore/page/scrolling/ScrollingTreeNode.h b/Source/WebCore/page/scrolling/ScrollingTreeNode.h
index d26293a89..258783e7d 100644
--- a/Source/WebCore/page/scrolling/ScrollingTreeNode.h
+++ b/Source/WebCore/page/scrolling/ScrollingTreeNode.h
@@ -29,6 +29,7 @@
#if ENABLE(THREADED_SCROLLING)
#include "IntRect.h"
+#include "ScrollTypes.h"
#include <wtf/PassOwnPtr.h>
namespace WebCore {
@@ -44,19 +45,37 @@ public:
virtual void update(ScrollingTreeState*);
virtual void handleWheelEvent(const PlatformWheelEvent&) = 0;
+ virtual void setScrollPosition(const IntPoint&) = 0;
protected:
explicit ScrollingTreeNode(ScrollingTree*);
ScrollingTree* scrollingTree() const { return m_scrollingTree; }
+
const IntRect& viewportRect() const { return m_viewportRect; }
const IntSize& contentsSize() const { return m_contentsSize; }
+ bool shouldUpdateScrollLayerPositionOnMainThread() const { return m_shouldUpdateScrollLayerPositionOnMainThread; }
+
+ ScrollElasticity horizontalScrollElasticity() const { return m_horizontalScrollElasticity; }
+ ScrollElasticity verticalScrollElasticity() const { return m_verticalScrollElasticity; }
+
+ bool hasEnabledHorizontalScrollbar() const { return m_hasEnabledHorizontalScrollbar; }
+ bool hasEnabledVerticalScrollbar() const { return m_hasEnabledVerticalScrollbar; }
+
private:
ScrollingTree* m_scrollingTree;
IntRect m_viewportRect;
IntSize m_contentsSize;
+
+ bool m_shouldUpdateScrollLayerPositionOnMainThread;
+
+ ScrollElasticity m_horizontalScrollElasticity;
+ ScrollElasticity m_verticalScrollElasticity;
+
+ bool m_hasEnabledHorizontalScrollbar;
+ bool m_hasEnabledVerticalScrollbar;
};
} // namespace WebCore
diff --git a/Source/WebCore/page/scrolling/ScrollingTreeState.cpp b/Source/WebCore/page/scrolling/ScrollingTreeState.cpp
index c368152c3..ebf648d2b 100644
--- a/Source/WebCore/page/scrolling/ScrollingTreeState.cpp
+++ b/Source/WebCore/page/scrolling/ScrollingTreeState.cpp
@@ -38,6 +38,11 @@ PassOwnPtr<ScrollingTreeState> ScrollingTreeState::create()
ScrollingTreeState::ScrollingTreeState()
: m_changedProperties(0)
, m_wheelEventHandlerCount(0)
+ , m_shouldUpdateScrollLayerPositionOnMainThread(false)
+ , m_horizontalScrollElasticity(ScrollElasticityNone)
+ , m_verticalScrollElasticity(ScrollElasticityNone)
+ , m_hasEnabledHorizontalScrollbar(false)
+ , m_hasEnabledVerticalScrollbar(false)
{
}
@@ -81,6 +86,51 @@ void ScrollingTreeState::setWheelEventHandlerCount(unsigned wheelEventHandlerCou
m_changedProperties |= WheelEventHandlerCount;
}
+void ScrollingTreeState::setShouldUpdateScrollLayerPositionOnMainThread(bool shouldUpdateScrollLayerPositionOnMainThread)
+{
+ if (m_shouldUpdateScrollLayerPositionOnMainThread == shouldUpdateScrollLayerPositionOnMainThread)
+ return;
+
+ m_shouldUpdateScrollLayerPositionOnMainThread = shouldUpdateScrollLayerPositionOnMainThread;
+ m_changedProperties |= ShouldUpdateScrollLayerPositionOnMainThread;
+}
+
+void ScrollingTreeState::setHorizontalScrollElasticity(ScrollElasticity horizontalScrollElasticity)
+{
+ if (m_horizontalScrollElasticity == horizontalScrollElasticity)
+ return;
+
+ m_horizontalScrollElasticity = horizontalScrollElasticity;
+ m_changedProperties |= HorizontalScrollElasticity;
+}
+
+void ScrollingTreeState::setVerticalScrollElasticity(ScrollElasticity verticalScrollElasticity)
+{
+ if (m_verticalScrollElasticity == verticalScrollElasticity)
+ return;
+
+ m_verticalScrollElasticity = verticalScrollElasticity;
+ m_changedProperties |= VerticalScrollElasticity;
+}
+
+void ScrollingTreeState::setHasEnabledHorizontalScrollbar(bool hasEnabledHorizontalScrollbar)
+{
+ if (m_hasEnabledHorizontalScrollbar == hasEnabledHorizontalScrollbar)
+ return;
+
+ m_hasEnabledHorizontalScrollbar = hasEnabledHorizontalScrollbar;
+ m_changedProperties |= HasEnabledHorizontalScrollbar;
+}
+
+void ScrollingTreeState::setHasEnabledVerticalScrollbar(bool hasEnabledVerticalScrollbar)
+{
+ if (m_hasEnabledVerticalScrollbar == hasEnabledVerticalScrollbar)
+ return;
+
+ m_hasEnabledVerticalScrollbar = hasEnabledVerticalScrollbar;
+ m_changedProperties |= HasEnabledVerticalScrollbar;
+}
+
PassOwnPtr<ScrollingTreeState> ScrollingTreeState::commit()
{
OwnPtr<ScrollingTreeState> treeState = adoptPtr(new ScrollingTreeState(*this));
diff --git a/Source/WebCore/page/scrolling/ScrollingTreeState.h b/Source/WebCore/page/scrolling/ScrollingTreeState.h
index fde884922..97cc77a94 100644
--- a/Source/WebCore/page/scrolling/ScrollingTreeState.h
+++ b/Source/WebCore/page/scrolling/ScrollingTreeState.h
@@ -31,6 +31,7 @@
#include "GraphicsLayer.h"
#include "IntRect.h"
#include "Region.h"
+#include "ScrollTypes.h"
#include <wtf/PassOwnPtr.h>
#if PLATFORM(MAC)
@@ -53,7 +54,12 @@ public:
ContentsSize = 1 << 1,
NonFastScrollableRegion = 1 << 2,
WheelEventHandlerCount = 1 << 3,
- ScrollLayer = 1 << 4,
+ ShouldUpdateScrollLayerPositionOnMainThread = 1 << 4,
+ HorizontalScrollElasticity = 1 << 5,
+ VerticalScrollElasticity = 1 << 6,
+ HasEnabledHorizontalScrollbar = 1 << 7,
+ HasEnabledVerticalScrollbar = 1 << 8,
+ ScrollLayer = 1 << 9,
};
bool hasChangedProperties() const { return m_changedProperties; }
@@ -71,6 +77,21 @@ public:
unsigned wheelEventHandlerCount() const { return m_wheelEventHandlerCount; }
void setWheelEventHandlerCount(unsigned);
+ bool shouldUpdateScrollLayerPositionOnMainThread() const { return m_shouldUpdateScrollLayerPositionOnMainThread; }
+ void setShouldUpdateScrollLayerPositionOnMainThread(bool);
+
+ ScrollElasticity horizontalScrollElasticity() const { return m_horizontalScrollElasticity; }
+ void setHorizontalScrollElasticity(ScrollElasticity);
+
+ ScrollElasticity verticalScrollElasticity() const { return m_verticalScrollElasticity; }
+ void setVerticalScrollElasticity(ScrollElasticity);
+
+ bool hasEnabledHorizontalScrollbar() const { return m_hasEnabledHorizontalScrollbar; }
+ void setHasEnabledHorizontalScrollbar(bool);
+
+ bool hasEnabledVerticalScrollbar() const { return m_hasEnabledVerticalScrollbar; }
+ void setHasEnabledVerticalScrollbar(bool);
+
PlatformLayer* platformScrollLayer() const;
void setScrollLayer(const GraphicsLayer*);
@@ -89,6 +110,14 @@ private:
unsigned m_wheelEventHandlerCount;
+ bool m_shouldUpdateScrollLayerPositionOnMainThread;
+
+ ScrollElasticity m_horizontalScrollElasticity;
+ ScrollElasticity m_verticalScrollElasticity;
+
+ bool m_hasEnabledHorizontalScrollbar;
+ bool m_hasEnabledVerticalScrollbar;
+
#if PLATFORM(MAC)
RetainPtr<PlatformLayer> m_platformScrollLayer;
#endif
diff --git a/Source/WebCore/page/scrolling/chromium/ScrollingCoordinatorChromium.cpp b/Source/WebCore/page/scrolling/chromium/ScrollingCoordinatorChromium.cpp
new file mode 100644
index 000000000..e590138a6
--- /dev/null
+++ b/Source/WebCore/page/scrolling/chromium/ScrollingCoordinatorChromium.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2012 Google 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 "ScrollingCoordinator.h"
+
+#include "LayerChromium.h"
+#include "Region.h"
+
+namespace WebCore {
+
+class ScrollingCoordinatorPrivate {
+WTF_MAKE_NONCOPYABLE(ScrollingCoordinatorPrivate);
+public:
+ ScrollingCoordinatorPrivate() { }
+ ~ScrollingCoordinatorPrivate() { }
+
+ void setScrollLayer(LayerChromium* layer) { m_scrollLayer = layer; }
+ LayerChromium* scrollLayer() const { return m_scrollLayer.get(); }
+
+private:
+ RefPtr<LayerChromium> m_scrollLayer;
+};
+
+PassRefPtr<ScrollingCoordinator> ScrollingCoordinator::create(Page* page)
+{
+ RefPtr<ScrollingCoordinator> coordinator(adoptRef(new ScrollingCoordinator(page)));
+ coordinator->m_private = new ScrollingCoordinatorPrivate;
+ return coordinator.release();
+}
+
+ScrollingCoordinator::~ScrollingCoordinator()
+{
+ ASSERT(!m_page);
+ delete m_private;
+}
+
+void ScrollingCoordinator::frameViewHorizontalScrollbarLayerDidChange(FrameView*, GraphicsLayer* horizontalScrollbarLayer)
+{
+ // FIXME: Implement!
+}
+
+void ScrollingCoordinator::frameViewVerticalScrollbarLayerDidChange(FrameView*, GraphicsLayer* verticalScrollbarLayer)
+{
+ // FIXME: Implement!
+}
+
+void ScrollingCoordinator::setScrollLayer(GraphicsLayer* scrollLayer)
+{
+ m_private->setScrollLayer(scrollLayer ? scrollLayer->platformLayer() : 0);
+}
+
+void ScrollingCoordinator::setNonFastScrollableRegion(const Region&)
+{
+ // FIXME: Implement!
+}
+
+void ScrollingCoordinator::setScrollParameters(ScrollElasticity horizontalScrollElasticity, ScrollElasticity verticalScrollElasticity,
+ bool hasEnabledHorizontalScrollbar, bool hasEnabledVerticalScrollbar,
+ const IntRect& viewportRect, const IntSize& contentsSize)
+{
+ // FIXME: Implement!
+}
+
+void ScrollingCoordinator::setWheelEventHandlerCount(unsigned wheelEventHandlerCount)
+{
+ if (LayerChromium* layer = m_private->scrollLayer())
+ layer->setHaveWheelEventHandlers(wheelEventHandlerCount > 0);
+}
+
+void ScrollingCoordinator::setShouldUpdateScrollLayerPositionOnMainThread(bool should)
+{
+ // FIXME: Implement!
+}
+
+}
diff --git a/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm b/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm
index 31fa76683..94335b0b2 100644
--- a/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm
+++ b/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm
@@ -42,6 +42,20 @@
namespace WebCore {
+class ScrollingCoordinatorPrivate {
+};
+
+PassRefPtr<ScrollingCoordinator> ScrollingCoordinator::create(Page* page)
+{
+ return adoptRef(new ScrollingCoordinator(page));
+}
+
+ScrollingCoordinator::~ScrollingCoordinator()
+{
+ ASSERT(!m_page);
+ ASSERT(!m_scrollingTree);
+}
+
void ScrollingCoordinator::frameViewHorizontalScrollbarLayerDidChange(FrameView* frameView, GraphicsLayer*)
{
ASSERT(isMainThread());
@@ -64,18 +78,6 @@ void ScrollingCoordinator::frameViewVerticalScrollbarLayerDidChange(FrameView* f
// FIXME: Implement.
}
-void ScrollingCoordinator::frameViewScrollLayerDidChange(FrameView* frameView, const GraphicsLayer* scrollLayer)
-{
- ASSERT(isMainThread());
- ASSERT(m_page);
-
- if (frameView->frame() != m_page->mainFrame())
- return;
-
- m_scrollingTreeState->setScrollLayer(scrollLayer);
- scheduleTreeStateCommit();
-}
-
} // namespace WebCore
#endif // ENABLE(THREADED_SCROLLING)
diff --git a/Source/WebCore/page/scrolling/mac/ScrollingTreeNodeMac.h b/Source/WebCore/page/scrolling/mac/ScrollingTreeNodeMac.h
index b1ae6ee76..97b3d22bc 100644
--- a/Source/WebCore/page/scrolling/mac/ScrollingTreeNodeMac.h
+++ b/Source/WebCore/page/scrolling/mac/ScrollingTreeNodeMac.h
@@ -28,6 +28,7 @@
#if ENABLE(THREADED_SCROLLING)
+#include "ScrollElasticityController.h"
#include "ScrollingTreeNode.h"
#include <wtf/RetainPtr.h>
@@ -35,18 +36,44 @@ OBJC_CLASS CALayer;
namespace WebCore {
-class ScrollingTreeNodeMac : public ScrollingTreeNode {
+class ScrollingTreeNodeMac : public ScrollingTreeNode, private ScrollElasticityControllerClient {
public:
explicit ScrollingTreeNodeMac(ScrollingTree*);
+ virtual ~ScrollingTreeNodeMac();
private:
+ // ScrollingTreeNode member functions.
virtual void update(ScrollingTreeState*) OVERRIDE;
virtual void handleWheelEvent(const PlatformWheelEvent&) OVERRIDE;
+ virtual void setScrollPosition(const IntPoint&) OVERRIDE;
+
+ // ScrollElasticityController member functions.
+ virtual bool allowsHorizontalStretching() OVERRIDE;
+ virtual bool allowsVerticalStretching() OVERRIDE;
+ virtual IntSize stretchAmount() OVERRIDE;
+ virtual bool pinnedInDirection(const FloatSize&) OVERRIDE;
+ virtual bool canScrollHorizontally() OVERRIDE;
+ virtual bool canScrollVertically() OVERRIDE;
+ virtual bool shouldRubberBandInDirection(ScrollDirection) OVERRIDE;
+ virtual IntPoint absoluteScrollPosition() OVERRIDE;
+ virtual void immediateScrollBy(const FloatSize&) OVERRIDE;
+ virtual void immediateScrollByWithoutContentEdgeConstraints(const FloatSize&) OVERRIDE;
+ virtual void startSnapRubberbandTimer() OVERRIDE;
+ virtual void stopSnapRubberbandTimer() OVERRIDE;
IntPoint scrollPosition() const;
- void setScrollPosition(const IntPoint&);
+ void setScrollLayerPosition(const IntPoint&);
+
+ IntPoint minimumScrollPosition() const;
+ IntPoint maximumScrollPosition() const;
void scrollBy(const IntSize&);
+ void scrollByWithoutContentEdgeConstraints(const IntSize&);
+
+ void updateMainFramePinState(const IntPoint& scrollPosition);
+
+ ScrollElasticityController m_scrollElasticityController;
+ RetainPtr<CFRunLoopTimerRef> m_snapRubberbandTimer;
RetainPtr<CALayer> m_scrollLayer;
};
diff --git a/Source/WebCore/page/scrolling/mac/ScrollingTreeNodeMac.mm b/Source/WebCore/page/scrolling/mac/ScrollingTreeNodeMac.mm
index 76a8e3eaf..966b2e18f 100644
--- a/Source/WebCore/page/scrolling/mac/ScrollingTreeNodeMac.mm
+++ b/Source/WebCore/page/scrolling/mac/ScrollingTreeNodeMac.mm
@@ -41,21 +41,175 @@ PassOwnPtr<ScrollingTreeNode> ScrollingTreeNode::create(ScrollingTree* scrolling
ScrollingTreeNodeMac::ScrollingTreeNodeMac(ScrollingTree* scrollingTree)
: ScrollingTreeNode(scrollingTree)
+ , m_scrollElasticityController(this)
{
}
+ScrollingTreeNodeMac::~ScrollingTreeNodeMac()
+{
+ if (m_snapRubberbandTimer)
+ CFRunLoopTimerInvalidate(m_snapRubberbandTimer.get());
+}
+
void ScrollingTreeNodeMac::update(ScrollingTreeState* state)
{
ScrollingTreeNode::update(state);
if (state->changedProperties() & ScrollingTreeState::ScrollLayer)
m_scrollLayer = state->platformScrollLayer();
+
+ if (state->changedProperties() & (ScrollingTreeState::ScrollLayer | ScrollingTreeState::ContentsSize | ScrollingTreeState::ViewportRect))
+ updateMainFramePinState(scrollPosition());
}
void ScrollingTreeNodeMac::handleWheelEvent(const PlatformWheelEvent& wheelEvent)
{
- // FXIME: This needs to handle rubberbanding.
- scrollBy(IntSize(-wheelEvent.deltaX(), -wheelEvent.deltaY()));
+ m_scrollElasticityController.handleWheelEvent(wheelEvent);
+}
+
+void ScrollingTreeNodeMac::setScrollPosition(const IntPoint& scrollPosition)
+{
+ updateMainFramePinState(scrollPosition);
+
+ if (shouldUpdateScrollLayerPositionOnMainThread()) {
+ scrollingTree()->updateMainFrameScrollPositionAndScrollLayerPosition(scrollPosition);
+ return;
+ }
+
+ setScrollLayerPosition(scrollPosition);
+ scrollingTree()->updateMainFrameScrollPosition(scrollPosition);
+}
+
+bool ScrollingTreeNodeMac::allowsHorizontalStretching()
+{
+ switch (horizontalScrollElasticity()) {
+ case ScrollElasticityAutomatic:
+ return hasEnabledHorizontalScrollbar() || !hasEnabledVerticalScrollbar();
+ case ScrollElasticityNone:
+ return false;
+ case ScrollElasticityAllowed:
+ return true;
+ }
+
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+bool ScrollingTreeNodeMac::allowsVerticalStretching()
+{
+ switch (verticalScrollElasticity()) {
+ case ScrollElasticityAutomatic:
+ return hasEnabledVerticalScrollbar() || !hasEnabledHorizontalScrollbar();
+ case ScrollElasticityNone:
+ return false;
+ case ScrollElasticityAllowed:
+ return true;
+ }
+
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+IntSize ScrollingTreeNodeMac::stretchAmount()
+{
+ IntSize stretch;
+
+ if (scrollPosition().y() < minimumScrollPosition().y())
+ stretch.setHeight(scrollPosition().y() - minimumScrollPosition().y());
+ else if (scrollPosition().y() > maximumScrollPosition().y())
+ stretch.setHeight(scrollPosition().y() - maximumScrollPosition().y());
+
+ if (scrollPosition().x() < minimumScrollPosition().x())
+ stretch.setWidth(scrollPosition().x() - minimumScrollPosition().x());
+ else if (scrollPosition().x() > maximumScrollPosition().x())
+ stretch.setWidth(scrollPosition().x() - maximumScrollPosition().x());
+
+ return stretch;
+}
+
+bool ScrollingTreeNodeMac::pinnedInDirection(const FloatSize& delta)
+{
+ FloatSize limitDelta;
+
+ if (fabsf(delta.height()) >= fabsf(delta.width())) {
+ if (delta.height() < 0) {
+ // We are trying to scroll up. Make sure we are not pinned to the top
+ limitDelta.setHeight(scrollPosition().y() - minimumScrollPosition().y());
+ } else {
+ // We are trying to scroll down. Make sure we are not pinned to the bottom
+ limitDelta.setHeight(maximumScrollPosition().y() - scrollPosition().y());
+ }
+ } else if (delta.width()) {
+ if (delta.width() < 0) {
+ // We are trying to scroll left. Make sure we are not pinned to the left
+ limitDelta.setHeight(scrollPosition().x() - minimumScrollPosition().x());
+ } else {
+ // We are trying to scroll right. Make sure we are not pinned to the right
+ limitDelta.setHeight(maximumScrollPosition().x() - scrollPosition().x());
+ }
+ }
+
+ if ((delta.width() || delta.height()) && (limitDelta.width() < 1 && limitDelta.height() < 1))
+ return true;
+
+ return false;
+}
+
+bool ScrollingTreeNodeMac::canScrollHorizontally()
+{
+ return hasEnabledHorizontalScrollbar();
+}
+
+bool ScrollingTreeNodeMac::canScrollVertically()
+{
+ return hasEnabledVerticalScrollbar();
+}
+
+bool ScrollingTreeNodeMac::shouldRubberBandInDirection(ScrollDirection direction)
+{
+ if (direction == ScrollLeft)
+ return !scrollingTree()->canGoBack();
+ if (direction == ScrollRight)
+ return !scrollingTree()->canGoForward();
+
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+IntPoint ScrollingTreeNodeMac::absoluteScrollPosition()
+{
+ return scrollPosition();
+}
+
+void ScrollingTreeNodeMac::immediateScrollBy(const FloatSize& offset)
+{
+ scrollBy(roundedIntSize(offset));
+}
+
+void ScrollingTreeNodeMac::immediateScrollByWithoutContentEdgeConstraints(const FloatSize& offset)
+{
+ scrollByWithoutContentEdgeConstraints(roundedIntSize(offset));
+}
+
+void ScrollingTreeNodeMac::startSnapRubberbandTimer()
+{
+ ASSERT(!m_snapRubberbandTimer);
+
+ CFTimeInterval timerInterval = 1.0 / 60.0;
+
+ m_snapRubberbandTimer = adoptCF(CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + timerInterval, timerInterval, 0, 0, ^(CFRunLoopTimerRef) {
+ m_scrollElasticityController.snapRubberBandTimerFired();
+ }));
+ CFRunLoopAddTimer(CFRunLoopGetCurrent(), m_snapRubberbandTimer.get(), kCFRunLoopDefaultMode);
+}
+
+void ScrollingTreeNodeMac::stopSnapRubberbandTimer()
+{
+ if (!m_snapRubberbandTimer)
+ return;
+
+ CFRunLoopTimerInvalidate(m_snapRubberbandTimer.get());
+ m_snapRubberbandTimer = nullptr;
}
IntPoint ScrollingTreeNodeMac::scrollPosition() const
@@ -64,16 +218,49 @@ IntPoint ScrollingTreeNodeMac::scrollPosition() const
return IntPoint(-scrollLayerPosition.x, -scrollLayerPosition.y);
}
-void ScrollingTreeNodeMac::setScrollPosition(const IntPoint& position)
+void ScrollingTreeNodeMac::setScrollLayerPosition(const IntPoint& position)
{
+ ASSERT(!shouldUpdateScrollLayerPositionOnMainThread());
m_scrollLayer.get().position = CGPointMake(-position.x(), -position.y());
}
-void ScrollingTreeNodeMac::scrollBy(const IntSize &offset)
+IntPoint ScrollingTreeNodeMac::minimumScrollPosition() const
+{
+ // FIXME: This should take the scroll origin into account.
+ return IntPoint(0, 0);
+}
+
+IntPoint ScrollingTreeNodeMac::maximumScrollPosition() const
+{
+ // FIXME: This should take the scroll origin into account.
+ IntPoint position(contentsSize().width() - viewportRect().width(),
+ contentsSize().height() - viewportRect().height());
+
+ position.clampNegativeToZero();
+
+ return position;
+}
+
+void ScrollingTreeNodeMac::scrollBy(const IntSize& offset)
+{
+ IntPoint newScrollPosition = scrollPosition() + offset;
+ newScrollPosition = newScrollPosition.shrunkTo(maximumScrollPosition());
+ newScrollPosition = newScrollPosition.expandedTo(minimumScrollPosition());
+
+ setScrollPosition(newScrollPosition);
+}
+
+void ScrollingTreeNodeMac::scrollByWithoutContentEdgeConstraints(const IntSize& offset)
{
setScrollPosition(scrollPosition() + offset);
+}
+
+void ScrollingTreeNodeMac::updateMainFramePinState(const IntPoint& scrollPosition)
+{
+ bool pinnedToTheLeft = scrollPosition.x() <= minimumScrollPosition().x();
+ bool pinnedToTheRight = scrollPosition.x() >= maximumScrollPosition().x();
- scrollingTree()->updateMainFrameScrollPosition(scrollPosition());
+ scrollingTree()->setMainFramePinState(pinnedToTheLeft, pinnedToTheRight);
}
} // namespace WebCore