summaryrefslogtreecommitdiff
path: root/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/page/scrolling/ScrollingCoordinator.cpp')
-rw-r--r--Source/WebCore/page/scrolling/ScrollingCoordinator.cpp252
1 files changed, 217 insertions, 35 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)