#include "config.h"
#include "ScrollingTree.h"
#if ENABLE(THREADED_SCROLLING)
#include "PlatformWheelEvent.h"
#include "ScrollingCoordinator.h"
#include "ScrollingThread.h"
#include "ScrollingTreeNode.h"
#include "ScrollingTreeState.h"
#include <wtf/MainThread.h>
namespace WebCore {
PassRefPtr<ScrollingTree> ScrollingTree::create(ScrollingCoordinator* scrollingCoordinator)
{
return adoptRef(new ScrollingTree(scrollingCoordinator));
}
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)
{
}
ScrollingTree::~ScrollingTree()
{
ASSERT(!m_scrollingCoordinator);
}
ScrollingTree::EventResult ScrollingTree::tryToHandleWheelEvent(const PlatformWheelEvent& wheelEvent)
{
{
MutexLocker lock(m_mutex);
if (m_hasWheelEventHandlers)
return SendToMainThread;
if (!m_nonFastScrollableRegion.isEmpty()) {
IntPoint position = wheelEvent.position();
position.moveBy(m_mainFrameScrollPosition);
if (m_nonFastScrollableRegion.contains(position))
return SendToMainThread;
}
}
if (willWheelEventStartSwipeGesture(wheelEvent))
return DidNotHandleEvent;
ScrollingThread::dispatch(bind(&ScrollingTree::handleWheelEvent, this, wheelEvent));
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)
{
ASSERT(ScrollingThread::isCurrentThread());
m_rootNode->handleWheelEvent(wheelEvent);
}
static void derefScrollingCoordinator(ScrollingCoordinator* scrollingCoordinator)
{
ASSERT(isMainThread());
scrollingCoordinator->deref();
}
void ScrollingTree::invalidate()
{
ASSERT(ScrollingThread::isCurrentThread());
callOnMainThread(bind(derefScrollingCoordinator, m_scrollingCoordinator.release().leakRef()));
}
void ScrollingTree::commitNewTreeState(PassOwnPtr<ScrollingTreeState> scrollingTreeState)
{
ASSERT(ScrollingThread::isCurrentThread());
if (scrollingTreeState->changedProperties() & (ScrollingTreeState::WheelEventHandlerCount | ScrollingTreeState::NonFastScrollableRegion | ScrollingTreeState::ScrollLayer)) {
MutexLocker lock(m_mutex);
if (scrollingTreeState->changedProperties() & ScrollingTreeState::ScrollLayer)
m_mainFrameScrollPosition = IntPoint();
if (scrollingTreeState->changedProperties() & ScrollingTreeState::WheelEventHandlerCount)
m_hasWheelEventHandlers = scrollingTreeState->wheelEventHandlerCount();
if (scrollingTreeState->changedProperties() & ScrollingTreeState::NonFastScrollableRegion)
m_nonFastScrollableRegion = scrollingTreeState->nonFastScrollableRegion();
}
m_rootNode->update(scrollingTreeState.get());
updateDebugRootLayer();
}
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)
return;
{
MutexLocker lock(m_mutex);
m_mainFrameScrollPosition = scrollPosition;
}
callOnMainThread(bind(&ScrollingCoordinator::updateMainFrameScrollPosition, m_scrollingCoordinator.get(), scrollPosition));
}
IntPoint ScrollingTree::mainFrameScrollPosition()
{
MutexLocker lock(m_mutex);
return m_mainFrameScrollPosition;
}
void ScrollingTree::updateMainFrameScrollPositionAndScrollLayerPosition(const IntPoint& scrollPosition)
{
if (!m_scrollingCoordinator)
return;
{
MutexLocker lock(m_mutex);
m_mainFrameScrollPosition = scrollPosition;
}
callOnMainThread(bind(&ScrollingCoordinator::updateMainFrameScrollPositionAndScrollLayerPosition, m_scrollingCoordinator.get()));
}
#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
void ScrollingTree::handleWheelEventPhase(PlatformWheelEventPhase phase)
{
if (!m_scrollingCoordinator)
return;
callOnMainThread(bind(&ScrollingCoordinator::handleWheelEventPhase, m_scrollingCoordinator.get(), phase));
}
#endif
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;
}
}
#endif // ENABLE(THREADED_SCROLLING)