Home | History | Annotate | Download | only in page
      1 /*
      2  * Copyright (C) 2013 Google Inc. All rights reserved.
      3  * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
      4  * Copyright (C) 2006 Alexey Proskuryakov (ap (at) webkit.org)
      5  * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies)
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include "config.h"
     30 #include "core/page/AutoscrollController.h"
     31 
     32 #include "core/page/EventHandler.h"
     33 #include "core/frame/Frame.h"
     34 #include "core/frame/FrameView.h"
     35 #include "core/page/Chrome.h"
     36 #include "core/page/Page.h"
     37 #include "core/rendering/HitTestResult.h"
     38 #include "core/rendering/RenderBox.h"
     39 #include "wtf/CurrentTime.h"
     40 
     41 namespace WebCore {
     42 
     43 // Delay time in second for start autoscroll if pointer is in border edge of scrollable element.
     44 static double autoscrollDelay = 0.2;
     45 
     46 PassOwnPtr<AutoscrollController> AutoscrollController::create(Page& page)
     47 {
     48     return adoptPtr(new AutoscrollController(page));
     49 }
     50 
     51 AutoscrollController::AutoscrollController(Page& page)
     52     : m_page(page)
     53     , m_autoscrollRenderer(0)
     54     , m_autoscrollType(NoAutoscroll)
     55     , m_dragAndDropAutoscrollStartTime(0)
     56 {
     57 }
     58 
     59 bool AutoscrollController::autoscrollInProgress() const
     60 {
     61     return m_autoscrollType == AutoscrollForSelection;
     62 }
     63 
     64 bool AutoscrollController::autoscrollInProgress(const RenderBox* renderer) const
     65 {
     66     return m_autoscrollRenderer == renderer;
     67 }
     68 
     69 void AutoscrollController::startAutoscrollForSelection(RenderObject* renderer)
     70 {
     71     // We don't want to trigger the autoscroll or the panScroll if it's already active
     72     if (m_autoscrollType != NoAutoscroll)
     73         return;
     74     RenderBox* scrollable = RenderBox::findAutoscrollable(renderer);
     75     if (!scrollable)
     76         return;
     77     m_autoscrollType = AutoscrollForSelection;
     78     m_autoscrollRenderer = scrollable;
     79     startAutoscroll();
     80 }
     81 
     82 void AutoscrollController::stopAutoscroll()
     83 {
     84     RenderBox* scrollable = m_autoscrollRenderer;
     85     m_autoscrollRenderer = 0;
     86 
     87     if (!scrollable)
     88         return;
     89 
     90     scrollable->stopAutoscroll();
     91 #if OS(WIN)
     92     if (panScrollInProgress()) {
     93         if (FrameView* view = scrollable->frame()->view()) {
     94             view->removePanScrollIcon();
     95             view->setCursor(pointerCursor());
     96         }
     97     }
     98 #endif
     99 
    100     m_autoscrollType = NoAutoscroll;
    101 }
    102 
    103 void AutoscrollController::stopAutoscrollIfNeeded(RenderObject* renderer)
    104 {
    105     if (m_autoscrollRenderer != renderer)
    106         return;
    107     m_autoscrollRenderer = 0;
    108     m_autoscrollType = NoAutoscroll;
    109 }
    110 
    111 void AutoscrollController::updateAutoscrollRenderer()
    112 {
    113     if (!m_autoscrollRenderer)
    114         return;
    115 
    116     RenderObject* renderer = m_autoscrollRenderer;
    117 
    118 #if OS(WIN)
    119     HitTestResult hitTest = renderer->frame()->eventHandler().hitTestResultAtPoint(m_panScrollStartPos, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
    120 
    121     if (Node* nodeAtPoint = hitTest.innerNode())
    122         renderer = nodeAtPoint->renderer();
    123 #endif
    124 
    125     while (renderer && !(renderer->isBox() && toRenderBox(renderer)->canAutoscroll()))
    126         renderer = renderer->parent();
    127     m_autoscrollRenderer = renderer && renderer->isBox() ? toRenderBox(renderer) : 0;
    128 }
    129 
    130 void AutoscrollController::updateDragAndDrop(Node* dropTargetNode, const IntPoint& eventPosition, double eventTime)
    131 {
    132     if (!dropTargetNode || !dropTargetNode->renderer()) {
    133         stopAutoscroll();
    134         return;
    135     }
    136 
    137     if (m_autoscrollRenderer && m_autoscrollRenderer->frame() != dropTargetNode->renderer()->frame())
    138         return;
    139 
    140     RenderBox* scrollable = RenderBox::findAutoscrollable(dropTargetNode->renderer());
    141     if (!scrollable) {
    142         stopAutoscroll();
    143         return;
    144     }
    145 
    146     Page* page = scrollable->frame() ? scrollable->frame()->page() : 0;
    147     if (!page) {
    148         stopAutoscroll();
    149         return;
    150     }
    151 
    152     IntSize offset = scrollable->calculateAutoscrollDirection(eventPosition);
    153     if (offset.isZero()) {
    154         stopAutoscroll();
    155         return;
    156     }
    157 
    158     m_dragAndDropAutoscrollReferencePosition = eventPosition + offset;
    159 
    160     if (m_autoscrollType == NoAutoscroll) {
    161         m_autoscrollType = AutoscrollForDragAndDrop;
    162         m_autoscrollRenderer = scrollable;
    163         m_dragAndDropAutoscrollStartTime = eventTime;
    164         startAutoscroll();
    165     } else if (m_autoscrollRenderer != scrollable) {
    166         m_dragAndDropAutoscrollStartTime = eventTime;
    167         m_autoscrollRenderer = scrollable;
    168     }
    169 }
    170 
    171 #if OS(WIN)
    172 void AutoscrollController::handleMouseReleaseForPanScrolling(Frame* frame, const PlatformMouseEvent& mouseEvent)
    173 {
    174     if (!frame->isMainFrame())
    175         return;
    176     switch (m_autoscrollType) {
    177     case AutoscrollForPan:
    178         if (mouseEvent.button() == MiddleButton)
    179             m_autoscrollType = AutoscrollForPanCanStop;
    180         break;
    181     case AutoscrollForPanCanStop:
    182         stopAutoscroll();
    183         break;
    184     }
    185 }
    186 
    187 bool AutoscrollController::panScrollInProgress() const
    188 {
    189     return m_autoscrollType == AutoscrollForPanCanStop || m_autoscrollType == AutoscrollForPan;
    190 }
    191 
    192 void AutoscrollController::startPanScrolling(RenderBox* scrollable, const IntPoint& lastKnownMousePosition)
    193 {
    194     // We don't want to trigger the autoscroll or the panScroll if it's already active
    195     if (m_autoscrollType != NoAutoscroll)
    196         return;
    197 
    198     m_autoscrollType = AutoscrollForPan;
    199     m_autoscrollRenderer = scrollable;
    200     m_panScrollStartPos = lastKnownMousePosition;
    201 
    202     if (FrameView* view = scrollable->frame()->view())
    203         view->addPanScrollIcon(lastKnownMousePosition);
    204     startAutoscroll();
    205 }
    206 #else
    207 bool AutoscrollController::panScrollInProgress() const
    208 {
    209     return false;
    210 }
    211 #endif
    212 
    213 // FIXME: This would get get better animation fidelity if it used the monotonicFrameBeginTime instead
    214 // of WTF::currentTime().
    215 void AutoscrollController::animate(double)
    216 {
    217     if (!m_autoscrollRenderer) {
    218         stopAutoscroll();
    219         return;
    220     }
    221 
    222     EventHandler& eventHandler = m_autoscrollRenderer->frame()->eventHandler();
    223     switch (m_autoscrollType) {
    224     case AutoscrollForDragAndDrop:
    225         if (WTF::currentTime() - m_dragAndDropAutoscrollStartTime > autoscrollDelay)
    226             m_autoscrollRenderer->autoscroll(m_dragAndDropAutoscrollReferencePosition);
    227         break;
    228     case AutoscrollForSelection:
    229         if (!eventHandler.mousePressed()) {
    230             stopAutoscroll();
    231             return;
    232         }
    233         eventHandler.updateSelectionForMouseDrag();
    234         m_autoscrollRenderer->autoscroll(eventHandler.lastKnownMousePosition());
    235         break;
    236     case NoAutoscroll:
    237         break;
    238 #if OS(WIN)
    239     case AutoscrollForPanCanStop:
    240     case AutoscrollForPan:
    241         if (!panScrollInProgress()) {
    242             stopAutoscroll();
    243             return;
    244         }
    245         if (FrameView* view = m_autoscrollRenderer->frame()->view())
    246             updatePanScrollState(view, eventHandler.lastKnownMousePosition());
    247         m_autoscrollRenderer->panScroll(m_panScrollStartPos);
    248         break;
    249 #endif
    250     }
    251     if (m_autoscrollType != NoAutoscroll)
    252         m_page.chrome().scheduleAnimation();
    253 }
    254 
    255 void AutoscrollController::startAutoscroll()
    256 {
    257     m_page.chrome().scheduleAnimation();
    258 }
    259 
    260 #if OS(WIN)
    261 void AutoscrollController::updatePanScrollState(FrameView* view, const IntPoint& lastKnownMousePosition)
    262 {
    263     // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll
    264     // So we don't want to change the cursor over this area
    265     bool east = m_panScrollStartPos.x() < (lastKnownMousePosition.x() - ScrollView::noPanScrollRadius);
    266     bool west = m_panScrollStartPos.x() > (lastKnownMousePosition.x() + ScrollView::noPanScrollRadius);
    267     bool north = m_panScrollStartPos.y() > (lastKnownMousePosition.y() + ScrollView::noPanScrollRadius);
    268     bool south = m_panScrollStartPos.y() < (lastKnownMousePosition.y() - ScrollView::noPanScrollRadius);
    269 
    270     if (m_autoscrollType == AutoscrollForPan && (east || west || north || south))
    271         m_autoscrollType = AutoscrollForPanCanStop;
    272 
    273     if (north) {
    274         if (east)
    275             view->setCursor(northEastPanningCursor());
    276         else if (west)
    277             view->setCursor(northWestPanningCursor());
    278         else
    279             view->setCursor(northPanningCursor());
    280     } else if (south) {
    281         if (east)
    282             view->setCursor(southEastPanningCursor());
    283         else if (west)
    284             view->setCursor(southWestPanningCursor());
    285         else
    286             view->setCursor(southPanningCursor());
    287     } else if (east)
    288         view->setCursor(eastPanningCursor());
    289     else if (west)
    290         view->setCursor(westPanningCursor());
    291     else
    292         view->setCursor(middlePanningCursor());
    293 }
    294 #endif
    295 
    296 } // namespace WebCore
    297