EventHandler.cpp 120 KB
Newer Older
darin's avatar
darin committed
1
/*
2
 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
ap's avatar
ap committed
3
 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
darin's avatar
darin committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
 *
 * 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 COMPUTER, INC. ``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 COMPUTER, INC. OR
 * 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 "EventHandler.h"

30
#include "AXObjectCache.h"
darin's avatar
darin committed
31
#include "CachedImage.h"
32
#include "Chrome.h"
mjs's avatar
mjs committed
33
#include "ChromeClient.h"
darin's avatar
darin committed
34
#include "Cursor.h"
35
#include "CursorList.h"
darin's avatar
darin committed
36
#include "Document.h"
37
#include "DragController.h"
38
#include "DragState.h"
bdakin's avatar
bdakin committed
39
#include "Editor.h"
darin's avatar
darin committed
40
#include "EventNames.h"
41
#include "EventQueue.h"
ddkilzer's avatar
ddkilzer committed
42
#include "FloatPoint.h"
43
#include "FloatRect.h"
adele's avatar
adele committed
44
#include "FocusController.h"
darin's avatar
darin committed
45
#include "Frame.h"
antti's avatar
antti committed
46
#include "FrameLoader.h"
47
#include "FrameSelection.h"
darin's avatar
darin committed
48 49
#include "FrameTree.h"
#include "FrameView.h"
50
#include "htmlediting.h"
darin's avatar
darin committed
51
#include "HTMLFrameElementBase.h"
52
#include "HTMLFrameSetElement.h"
darin's avatar
darin committed
53 54
#include "HTMLInputElement.h"
#include "HTMLNames.h"
55 56
#include "HitTestRequest.h"
#include "HitTestResult.h"
57
#include "Image.h"
58
#include "InspectorInstrumentation.h"
darin's avatar
darin committed
59 60 61
#include "KeyboardEvent.h"
#include "MouseEvent.h"
#include "MouseEventWithHitTestResults.h"
adele's avatar
adele committed
62
#include "Page.h"
adele's avatar
adele committed
63
#include "PlatformKeyboardEvent.h"
darin's avatar
darin committed
64
#include "PlatformWheelEvent.h"
65
#include "PluginDocument.h"
66
#include "RenderFrameSet.h"
67
#include "RenderLayer.h"
68
#include "RenderTextControlSingleLine.h"
eric@webkit.org's avatar
eric@webkit.org committed
69
#include "RenderView.h"
70
#include "RenderWidget.h"
71
#include "ScrollAnimator.h"
72
#include "Scrollbar.h"
darin's avatar
darin committed
73
#include "Settings.h"
74
#include "SpatialNavigation.h"
75
#include "StyleCachedImage.h"
darin's avatar
darin committed
76
#include "TextEvent.h"
77
#include "TextIterator.h"
78
#include "UserGestureIndicator.h"
79
#include "UserTypingGestureIndicator.h"
80
#include "WheelEvent.h"
ap@apple.com's avatar
ap@apple.com committed
81
#include "WindowsKeyboardCodes.h"
82
#include <wtf/Assertions.h>
83
#include <wtf/CurrentTime.h>
84
#include <wtf/StdLibExtras.h>
darin's avatar
darin committed
85

86 87 88 89
#if ENABLE(GESTURE_EVENTS)
#include "PlatformGestureEvent.h"
#endif

mjs's avatar
mjs committed
90
#if ENABLE(SVG)
weinig's avatar
weinig committed
91
#include "SVGDocument.h"
92
#include "SVGElementInstance.h"
darin's avatar
darin committed
93
#include "SVGNames.h"
94
#include "SVGUseElement.h"
darin's avatar
darin committed
95 96
#endif

97 98 99
#if ENABLE(TOUCH_EVENTS)
#include "PlatformTouchEvent.h"
#include "TouchEvent.h"
100
#include "TouchList.h"
101 102
#endif

103
#if ENABLE(GESTURE_RECOGNIZER)
104 105 106
#include "PlatformGestureRecognizer.h"
#endif

darin's avatar
darin committed
107 108 109 110
namespace WebCore {

using namespace HTMLNames;

bolsinga@apple.com's avatar
bolsinga@apple.com committed
111
#if ENABLE(DRAG_SUPPORT)
aliceli1's avatar
aliceli1 committed
112 113 114
// The link drag hysteresis is much larger than the others because there
// needs to be enough space to cancel the link press without starting a link drag,
// and because dragging links is rare.
oliver's avatar
 
oliver committed
115 116 117 118
const int LinkDragHysteresis = 40;
const int ImageDragHysteresis = 5;
const int TextDragHysteresis = 3;
const int GeneralDragHysteresis = 3;
bolsinga@apple.com's avatar
bolsinga@apple.com committed
119
#endif // ENABLE(DRAG_SUPPORT)
aliceli1's avatar
aliceli1 committed
120

oliver's avatar
oliver committed
121 122 123 124
// Match key code of composition keydown event on windows.
// IE sends VK_PROCESSKEY which has value 229;
const int CompositionEventKeyCode = 229;

mjs's avatar
mjs committed
125
#if ENABLE(SVG)
darin's avatar
darin committed
126 127 128
using namespace SVGNames;
#endif

129 130
// When the autoscroll or the panScroll is triggered when do the scroll every 0.05s to make it smooth
const double autoscrollInterval = 0.05;
darin's avatar
darin committed
131

132 133
const double fakeMouseMoveInterval = 0.1;

134
static inline bool scrollNode(float delta, WheelEvent::Granularity granularity, ScrollDirection positiveDirection, ScrollDirection negativeDirection, Node* node, Node** stopNode)
135
{
136
    if (!delta)
137 138
        return false;
    
139 140 141
    if (!node->renderer())
        return false;
    
142 143 144
    // Find the nearest enclosing box.
    RenderBox* enclosingBox = node->renderer()->enclosingBox();

145 146 147 148 149 150 151
    float absDelta = delta > 0 ? delta : -delta;
    
    if (granularity == WheelEvent::Page)
        return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPage, absDelta, stopNode);

    if (granularity == WheelEvent::Line)
        return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByLine, absDelta, stopNode);
152

153 154 155 156
    if (granularity == WheelEvent::Pixel)
        return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, absDelta, stopNode);
        
    return false;
157 158
}

159
#if !PLATFORM(MAC)
darin@apple.com's avatar
darin@apple.com committed
160 161 162 163 164 165

inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
{
    return false;
}

166
#if ENABLE(DRAG_SUPPORT)
darin@apple.com's avatar
darin@apple.com committed
167 168 169 170
inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
{
    return false;
}
171
#endif
darin@apple.com's avatar
darin@apple.com committed
172 173 174

#endif

darin's avatar
darin committed
175 176 177
EventHandler::EventHandler(Frame* frame)
    : m_frame(frame)
    , m_mousePressed(false)
178
    , m_capturesDragging(false)
darin's avatar
darin committed
179
    , m_mouseDownMayStartSelect(false)
bolsinga@apple.com's avatar
bolsinga@apple.com committed
180
#if ENABLE(DRAG_SUPPORT)
darin's avatar
darin committed
181
    , m_mouseDownMayStartDrag(false)
182
    , m_dragMayStartSelectionInstead(false)
bolsinga@apple.com's avatar
bolsinga@apple.com committed
183
#endif
darin's avatar
darin committed
184
    , m_mouseDownWasSingleClickInSelection(false)
darin's avatar
darin committed
185
    , m_beganSelectingText(false)
186
    , m_panScrollInProgress(false)
187 188
    , m_panScrollButtonPressed(false)
    , m_springLoadedPanScrollInProgress(false)
darin's avatar
darin committed
189 190 191
    , m_hoverTimer(this, &EventHandler::hoverTimerFired)
    , m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired)
    , m_autoscrollRenderer(0)
192
    , m_autoscrollInProgress(false)
darin's avatar
darin committed
193
    , m_mouseDownMayStartAutoscroll(false)
darin's avatar
darin committed
194
    , m_mouseDownWasInSubframe(false)
195
    , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired)
weinig's avatar
weinig committed
196 197 198
#if ENABLE(SVG)
    , m_svgPan(false)
#endif
darin's avatar
darin committed
199
    , m_resizeLayer(0)
ap@apple.com's avatar
ap@apple.com committed
200
    , m_eventHandlerWillResetCapturingMouseEventsNode(0)
darin's avatar
darin committed
201
    , m_clickCount(0)
aliceli1's avatar
aliceli1 committed
202
    , m_mouseDownTimestamp(0)
andersca@apple.com's avatar
andersca@apple.com committed
203 204
    , m_useLatchedWheelEventNode(false)
    , m_widgetIsLatched(false)
205
#if PLATFORM(MAC)
darin's avatar
darin committed
206 207
    , m_mouseDownView(nil)
    , m_sendingEventToSubview(false)
208
    , m_activationEventNumber(-1)
darin's avatar
darin committed
209
#endif
210 211 212
#if ENABLE(TOUCH_EVENTS)
    , m_touchPressed(false)
#endif
213
#if ENABLE(GESTURE_RECOGNIZER)
214 215
    , m_gestureRecognizer(PlatformGestureRecognizer::create())
#endif
darin's avatar
darin committed
216 217 218 219 220
{
}

EventHandler::~EventHandler()
{
221
    ASSERT(!m_fakeMouseMoveEventTimer.isActive());
darin's avatar
darin committed
222
}
oliver's avatar
 
oliver committed
223
    
bolsinga@apple.com's avatar
bolsinga@apple.com committed
224
#if ENABLE(DRAG_SUPPORT)
225
DragState& EventHandler::dragState()
oliver's avatar
 
oliver committed
226
{
227
    DEFINE_STATIC_LOCAL(DragState, state, ());
oliver's avatar
 
oliver committed
228 229
    return state;
}
bolsinga@apple.com's avatar
bolsinga@apple.com committed
230
#endif // ENABLE(DRAG_SUPPORT)
oliver's avatar
 
oliver committed
231
    
darin's avatar
darin committed
232 233 234
void EventHandler::clear()
{
    m_hoverTimer.stop();
235
    m_fakeMouseMoveEventTimer.stop();
darin's avatar
darin committed
236 237 238
    m_resizeLayer = 0;
    m_nodeUnderMouse = 0;
    m_lastNodeUnderMouse = 0;
239 240 241 242
#if ENABLE(SVG)
    m_instanceUnderMouse = 0;
    m_lastInstanceUnderMouse = 0;
#endif
darin's avatar
darin committed
243 244 245 246 247
    m_lastMouseMoveEventSubframe = 0;
    m_lastScrollbarUnderMouse = 0;
    m_clickCount = 0;
    m_clickNode = 0;
    m_frameSetBeingResized = 0;
bolsinga@apple.com's avatar
bolsinga@apple.com committed
248
#if ENABLE(DRAG_SUPPORT)
darin's avatar
darin committed
249
    m_dragTarget = 0;
250
    m_shouldOnlyFireDragOverEvent = false;
bolsinga@apple.com's avatar
bolsinga@apple.com committed
251
#endif
darin's avatar
darin committed
252 253 254
    m_currentMousePosition = IntPoint();
    m_mousePressNode = 0;
    m_mousePressed = false;
255
    m_capturesDragging = false;
256
    m_capturingMouseEventsNode = 0;
andersca@apple.com's avatar
andersca@apple.com committed
257
    m_latchedWheelEventNode = 0;
258
    m_previousWheelScrolledNode = 0;
259 260 261
#if ENABLE(TOUCH_EVENTS)
    m_originatingTouchPointTargets.clear();
#endif
darin's avatar
darin committed
262 263
}

264 265 266 267 268 269
void EventHandler::nodeWillBeRemoved(Node* nodeToBeRemoved)
{
    if (nodeToBeRemoved->contains(m_clickNode.get()))
        m_clickNode = 0;
}

270
static void setSelectionIfNeeded(FrameSelection* selection, const VisibleSelection& newSelection)
271 272 273 274 275 276
{
    ASSERT(selection);
    if (selection->selection() != newSelection && selection->shouldChangeSelection(newSelection))
        selection->setSelection(newSelection);
}

277
static void setNonDirectionalSelectionIfNeeded(FrameSelection* selection, const VisibleSelection& newSelection, TextGranularity granularity)
278 279 280 281 282 283
{
    ASSERT(selection);
    if (selection->selection() != newSelection && selection->shouldChangeSelection(newSelection))
        selection->setSelection(newSelection, granularity, MakeNonDirectionalSelection);
}

284
void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
darin's avatar
darin committed
285
{
286
    Node* innerNode = targetNode(result);
287
    VisibleSelection newSelection;
darin's avatar
darin committed
288

adele's avatar
adele committed
289
    if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
290
        VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
291
        TextGranularity granularity = CharacterGranularity;
darin's avatar
darin committed
292
        if (pos.isNotNull()) {
293
            newSelection = VisibleSelection(pos);
darin's avatar
darin committed
294 295 296
            newSelection.expandUsingGranularity(WordGranularity);
        }
    
297
        if (newSelection.isRange()) {
298
            granularity = WordGranularity;
299
            m_beganSelectingText = true;
300 301
            if (result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled()) 
                newSelection.appendTrailingWhitespace();            
302
        }
303 304

        setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, granularity);
darin's avatar
darin committed
305 306 307
    }
}

mitz@apple.com's avatar
mitz@apple.com committed
308 309 310 311 312
void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
{
    if (!result.hitTestResult().isLiveLink())
        return selectClosestWordFromMouseEvent(result);

313
    Node* innerNode = targetNode(result);
mitz@apple.com's avatar
mitz@apple.com committed
314 315

    if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
316
        VisibleSelection newSelection;
mitz@apple.com's avatar
mitz@apple.com committed
317 318
        Element* URLElement = result.hitTestResult().URLElement();
        VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
319
        if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement))
320
            newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
mitz@apple.com's avatar
mitz@apple.com committed
321
    
322
        TextGranularity granularity = CharacterGranularity;
mitz@apple.com's avatar
mitz@apple.com committed
323
        if (newSelection.isRange()) {
324
            granularity = WordGranularity;
mitz@apple.com's avatar
mitz@apple.com committed
325 326 327
            m_beganSelectingText = true;
        }

328
        setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, granularity);
mitz@apple.com's avatar
mitz@apple.com committed
329 330 331
    }
}

aroben's avatar
aroben committed
332
bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
darin's avatar
darin committed
333
{
aroben's avatar
aroben committed
334 335 336
    if (event.event().button() != LeftButton)
        return false;

darin@apple.com's avatar
darin@apple.com committed
337
    if (m_frame->selection()->isRange())
aroben's avatar
aroben committed
338 339 340 341 342 343 344
        // A double-click when range is already selected
        // should not change the selection.  So, do not call
        // selectClosestWordFromMouseEvent, but do set
        // m_beganSelectingText to prevent handleMouseReleaseEvent
        // from setting caret selection.
        m_beganSelectingText = true;
    else
345
        selectClosestWordFromMouseEvent(event);
aroben's avatar
aroben committed
346 347

    return true;
darin's avatar
darin committed
348 349
}

aroben's avatar
aroben committed
350
bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
darin's avatar
darin committed
351
{
aroben's avatar
aroben committed
352 353
    if (event.event().button() != LeftButton)
        return false;
darin's avatar
darin committed
354
    
355
    Node* innerNode = targetNode(event);
adele's avatar
adele committed
356
    if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
aroben's avatar
aroben committed
357 358
        return false;

359
    VisibleSelection newSelection;
360
    VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
aroben's avatar
aroben committed
361
    if (pos.isNotNull()) {
362
        newSelection = VisibleSelection(pos);
aroben's avatar
aroben committed
363
        newSelection.expandUsingGranularity(ParagraphGranularity);
darin's avatar
darin committed
364
    }
365 366
    
    TextGranularity granularity = CharacterGranularity;
aroben's avatar
aroben committed
367
    if (newSelection.isRange()) {
368
        granularity = ParagraphGranularity;
aroben's avatar
aroben committed
369 370
        m_beganSelectingText = true;
    }
371 372

    setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, granularity);
aroben's avatar
aroben committed
373 374

    return true;
darin's avatar
darin committed
375 376
}

377 378
static int textDistance(const Position& start, const Position& end)
{
379
     RefPtr<Range> range = Range::create(start.anchorNode()->document(), start, end);
380 381 382
     return TextIterator::rangeLength(range.get(), true);
}

aroben's avatar
aroben committed
383
bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
darin's avatar
darin committed
384
{
385
    Node* innerNode = targetNode(event);
adele's avatar
adele committed
386
    if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
aroben's avatar
aroben committed
387
        return false;
darin's avatar
darin committed
388

aroben's avatar
aroben committed
389 390
    // Extend the selection if the Shift key is down, unless the click is in a link.
    bool extendSelection = event.event().shiftKey() && !event.isOverLink();
darin's avatar
darin committed
391

aroben's avatar
aroben committed
392 393
    // Don't restart the selection when the mouse is pressed on an
    // existing selection so we can allow for text dragging.
394 395 396 397 398 399
    if (FrameView* view = m_frame->view()) {
        IntPoint vPoint = view->windowToContents(event.event().pos());
        if (!extendSelection && m_frame->selection()->contains(vPoint)) {
            m_mouseDownWasSingleClickInSelection = true;
            return false;
        }
darin's avatar
darin committed
400
    }
aroben's avatar
aroben committed
401

402
    VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint()));
aroben's avatar
aroben committed
403
    if (visiblePos.isNull())
404
        visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOWNSTREAM);
aroben's avatar
aroben committed
405 406
    Position pos = visiblePos.deepEquivalent();
    
407
    VisibleSelection newSelection = m_frame->selection()->selection();
408 409
    TextGranularity granularity = CharacterGranularity;

aroben's avatar
aroben committed
410
    if (extendSelection && newSelection.isCaretOrRange()) {
411
        m_frame->selection()->setIsDirectional(false);
aroben's avatar
aroben committed
412
        
413
        ASSERT(m_frame->settings());
414
        if (m_frame->settings()->editingBehaviorType() == EditingMacBehavior) {
415 416 417 418 419 420 421 422 423 424 425 426 427
            // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
            // was created right-to-left
            Position start = newSelection.start();
            Position end = newSelection.end();
            int distanceToStart = textDistance(start, pos);
            int distanceToEnd = textDistance(pos, end);
            if (distanceToStart <= distanceToEnd)
                newSelection = VisibleSelection(end, pos);
            else
                newSelection = VisibleSelection(start, pos);
        } else {
            newSelection.setExtent(pos);
        }
aroben's avatar
aroben committed
428

429 430 431
        if (m_frame->selection()->granularity() != CharacterGranularity) {
            granularity = m_frame->selection()->granularity();
            newSelection.expandUsingGranularity(m_frame->selection()->granularity());
432 433
        }

aroben's avatar
aroben committed
434
        m_beganSelectingText = true;
435
    } else
436
        newSelection = VisibleSelection(visiblePos);
437 438

    setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, granularity);
aroben's avatar
aroben committed
439 440

    return true;
darin's avatar
darin committed
441 442
}

aroben's avatar
aroben committed
443
bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
darin's avatar
darin committed
444
{
bolsinga@apple.com's avatar
bolsinga@apple.com committed
445
#if ENABLE(DRAG_SUPPORT)
446 447
    // Reset drag state.
    dragState().m_dragSrc = 0;
bolsinga@apple.com's avatar
bolsinga@apple.com committed
448
#endif
449

450 451
    cancelFakeMouseMoveEvent();

452 453 454 455 456
    if (ScrollView* scrollView = m_frame->view()) {
        if (scrollView->isPointInScrollbarCorner(event.event().pos()))
            return false;
    }

darin's avatar
darin committed
457 458 459 460
    bool singleClick = event.event().clickCount() <= 1;

    // If we got the event back, that must mean it wasn't prevented,
    // so it's allowed to start a drag or selection.
461
    m_mouseDownMayStartSelect = canMouseDownStartSelect(targetNode(event));
darin's avatar
darin committed
462
    
bolsinga@apple.com's avatar
bolsinga@apple.com committed
463
#if ENABLE(DRAG_SUPPORT)
darin's avatar
darin committed
464 465
    // Careful that the drag starting logic stays in sync with eventMayStartDrag()
    m_mouseDownMayStartDrag = singleClick;
bolsinga@apple.com's avatar
bolsinga@apple.com committed
466
#endif
darin's avatar
darin committed
467

darin's avatar
darin committed
468 469
    m_mouseDownWasSingleClickInSelection = false;

470 471
    m_mouseDown = event.event();

472
    if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
aroben's avatar
aroben committed
473
        return true;
darin's avatar
darin committed
474

weinig's avatar
weinig committed
475
#if ENABLE(SVG)
476 477
    if (m_frame->document()->isSVGDocument()
        && static_cast<SVGDocument*>(m_frame->document())->zoomAndPanEnabled()) {
weinig's avatar
weinig committed
478 479 480 481 482 483 484 485
        if (event.event().shiftKey() && singleClick) {
            m_svgPan = true;
            static_cast<SVGDocument*>(m_frame->document())->startPan(event.event().pos());
            return true;
        }
    }
#endif

darin's avatar
darin committed
486 487 488 489 490
    // We don't do this at the start of mouse down handling,
    // because we don't want to do it until we know we didn't hit a widget.
    if (singleClick)
        focusDocumentView();

491
    Node* innerNode = targetNode(event);
darin's avatar
darin committed
492 493

    m_mousePressNode = innerNode;
bolsinga@apple.com's avatar
bolsinga@apple.com committed
494
#if ENABLE(DRAG_SUPPORT)
darin's avatar
darin committed
495
    m_dragStartPos = event.event().pos();
bolsinga@apple.com's avatar
bolsinga@apple.com committed
496
#endif
darin's avatar
darin committed
497

aroben's avatar
aroben committed
498
    bool swallowEvent = false;
ap@webkit.org's avatar
ap@webkit.org committed
499 500 501 502 503 504 505 506 507
    m_mousePressed = true;
    m_beganSelectingText = false;

    if (event.event().clickCount() == 2)
        swallowEvent = handleMousePressEventDoubleClick(event);
    else if (event.event().clickCount() >= 3)
        swallowEvent = handleMousePressEventTripleClick(event);
    else
        swallowEvent = handleMousePressEventSingleClick(event);
darin's avatar
darin committed
508
    
509 510
    m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
        || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled(true));
aroben's avatar
aroben committed
511

512
    return swallowEvent;
darin's avatar
darin committed
513 514
}

515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
// There are two kinds of renderer that can autoscroll.
static bool canAutoscroll(RenderObject* renderer)
{
    if (!renderer->isBox())
        return false;

    // Check for a box that can be scrolled in its own right.
    if (toRenderBox(renderer)->canBeScrolledAndHasScrollableArea())
        return true;

    // Check for a box that represents the top level of a web page.
    // This can be scrolled by calling Chrome::scrollRectIntoView.
    // This only has an effect on the Mac platform in applications
    // that put web views into scrolling containers, such as Mac OS X Mail.
    // The code for this is in RenderLayer::scrollRectToVisible.
    if (renderer->node() != renderer->document())
        return false;
532
    Frame* frame = renderer->frame();
533 534 535 536 537 538
    if (!frame)
        return false;
    Page* page = frame->page();
    return page && page->mainFrame() == frame;
}

bolsinga@apple.com's avatar
bolsinga@apple.com committed
539
#if ENABLE(DRAG_SUPPORT)
540
bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
darin's avatar
darin committed
541 542
{
    if (handleDrag(event))
aroben's avatar
aroben committed
543
        return true;
darin's avatar
darin committed
544

ap's avatar
ap committed
545
    if (!m_mousePressed)
aroben's avatar
aroben committed
546
        return false;
darin's avatar
darin committed
547

548
    Node* targetNode = EventHandler::targetNode(event);
darin's avatar
darin committed
549
    if (event.event().button() != LeftButton || !targetNode || !targetNode->renderer())
aroben's avatar
aroben committed
550
        return false;
darin's avatar
darin committed
551 552 553 554 555 556 557

#if PLATFORM(MAC) // FIXME: Why does this assertion fire on other platforms?
    ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll);
#endif

    m_mouseDownMayStartDrag = false;

558
    if (m_mouseDownMayStartAutoscroll && !m_panScrollInProgress) {            
559
        // Find a renderer that can autoscroll.
darin's avatar
darin committed
560
        RenderObject* renderer = targetNode->renderer();
561
        while (renderer && !canAutoscroll(renderer)) {
562 563 564 565 566 567
            if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement())
                renderer = renderer->document()->ownerElement()->renderer();
            else
                renderer = renderer->parent();
        }
        
568 569
        if (renderer) {
            m_autoscrollInProgress = true;
darin's avatar
darin committed
570
            handleAutoscroll(renderer);
571
        }
572 573
        
        m_mouseDownMayStartAutoscroll = false;
darin's avatar
darin committed
574
    }
575 576 577 578 579

    if (!m_beganSelectingText) {
        HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
        HitTestResult result(m_mouseDownPos);
        m_frame->document()->renderView()->layer()->hitTest(request, result);
580 581

        updateSelectionForMouseDrag(result);
582
    }
583
    updateSelectionForMouseDrag(event.hitTestResult());
aroben's avatar
aroben committed
584
    return true;
darin's avatar
darin committed
585
}
oliver's avatar
 
oliver committed
586 587 588 589 590 591 592
    
bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
{
    // This is a pre-flight check of whether the event might lead to a drag being started.  Be careful
    // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag
    // in handleMousePressEvent
    
593 594 595 596
    if (!m_frame->contentRenderer() || !m_frame->contentRenderer()->hasLayer())
        return false;

    if (event.button() != LeftButton || event.clickCount() != 1)
oliver's avatar
 
oliver committed
597 598
        return false;
    
599 600 601 602
    FrameView* view = m_frame->view();
    if (!view)
        return false;

603 604 605 606
    Page* page = m_frame->page();
    if (!page)
        return false;

607
    updateDragSourceActionsAllowed();
608
    HitTestRequest request(HitTestRequest::ReadOnly);
609
    HitTestResult result(view->windowToContents(event.pos()));
eric@webkit.org's avatar
eric@webkit.org committed
610
    m_frame->contentRenderer()->layer()->hitTest(request, result);
611 612
    DragState state;
    return result.innerNode() && page->dragController()->draggableNode(m_frame, result.innerNode(), result.point(), state);
oliver's avatar
 
oliver committed
613
}
darin's avatar
darin committed
614

darin's avatar
darin committed
615 616 617 618 619
void EventHandler::updateSelectionForMouseDrag()
{
    FrameView* view = m_frame->view();
    if (!view)
        return;
620
    RenderView* renderer = m_frame->contentRenderer();
darin's avatar
darin committed
621 622 623 624 625 626
    if (!renderer)
        return;
    RenderLayer* layer = renderer->layer();
    if (!layer)
        return;

627 628 629
    HitTestRequest request(HitTestRequest::ReadOnly |
                           HitTestRequest::Active |
                           HitTestRequest::MouseMove);
darin's avatar
darin committed
630
    HitTestResult result(view->windowToContents(m_currentMousePosition));
631
    layer->hitTest(request, result);
632
    updateSelectionForMouseDrag(result);
darin's avatar
darin committed
633 634
}

635 636 637 638 639
static VisiblePosition selectionExtentRespectingEditingBoundary(const VisibleSelection& selection, const IntPoint& localPoint, Node* targetNode)
{
    IntPoint selectionEndPoint = localPoint;
    Element* editableElement = selection.rootEditableElement();

640 641
    if (!targetNode->renderer())
        return VisiblePosition();
642

643 644
    if (editableElement && !editableElement->contains(targetNode)) {
        if (!editableElement->renderer())
645 646 647
            return VisiblePosition();

        FloatPoint absolutePoint = targetNode->renderer()->localToAbsolute(FloatPoint(selectionEndPoint));
648 649
        selectionEndPoint = roundedIntPoint(editableElement->renderer()->absoluteToLocal(absolutePoint));
        targetNode = editableElement;
650 651
    }

652
    return targetNode->renderer()->positionForPoint(selectionEndPoint);
653 654
}

655
void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
darin's avatar
darin committed
656
{
darin's avatar
darin committed
657 658 659
    if (!m_mouseDownMayStartSelect)
        return;

660 661
    Node* target = targetNode(hitTestResult);
    if (!target)
darin's avatar
darin committed
662 663
        return;

664
    if (!canMouseDragExtendSelect(target))
665 666
        return;

667
    VisiblePosition targetPosition = selectionExtentRespectingEditingBoundary(m_frame->selection()->selection(), hitTestResult.localPoint(), target);
darin's avatar
darin committed
668

darin's avatar
darin committed
669
    // Don't modify the selection if we're not on a node.
darin's avatar
darin committed
670
    if (targetPosition.isNull())
darin's avatar
darin committed
671 672 673 674
        return;

    // Restart the selection if this is the first mouse move. This work is usually
    // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
675
    VisibleSelection newSelection = m_frame->selection()->selection();
darin's avatar
darin committed
676 677 678 679

#if ENABLE(SVG)
    // Special case to limit selection to the containing block for SVG text.
    // FIXME: Isn't there a better non-SVG-specific way to do this?
680
    if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
darin's avatar
darin committed
681 682
        if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
            if (selectionBaseRenderer->isSVGText())
683
                if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
darin's avatar
darin committed
684 685 686
                    return;
#endif

darin's avatar
darin committed
687 688
    if (!m_beganSelectingText) {
        m_beganSelectingText = true;
689
        newSelection = VisibleSelection(targetPosition);
darin's avatar
darin committed
690 691
    }

darin's avatar
darin committed
692
    newSelection.setExtent(targetPosition);
693 694
    if (m_frame->selection()->granularity() != CharacterGranularity)
        newSelection.expandUsingGranularity(m_frame->selection()->granularity());
darin's avatar
darin committed
695

696
    setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, m_frame->selection()->granularity());
darin's avatar
darin committed
697
}
bolsinga@apple.com's avatar
bolsinga@apple.com committed
698
#endif // ENABLE(DRAG_SUPPORT)
699 700 701 702 703 704

void EventHandler::lostMouseCapture()
{
    m_frame->selection()->setCaretBlinkingSuspended(false);
}

705 706 707 708 709 710 711 712 713 714 715 716
bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event)
{
    if (eventLoopHandleMouseUp(event))
        return true;
    
    // If this was the first click in the window, we don't even want to clear the selection.
    // This case occurs when the user clicks on a draggable element, since we have to process
    // the mouse down and drag events to see if we might start a drag.  For other first clicks
    // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets
    // ignored upstream of this layer.
    return eventActivatedView(event.event());
}    
darin's avatar
darin committed
717

aroben's avatar
aroben committed
718
bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
darin's avatar
darin committed
719
{
720 721
    if (m_autoscrollInProgress)
        stopAutoscrollTimer();
darin's avatar
darin committed
722 723

    if (handleMouseUp(event))
aroben's avatar
aroben committed
724
        return true;
darin's avatar
darin committed
725 726 727

    // Used to prevent mouseMoveEvent from initiating a drag before
    // the mouse is pressed again.
darin@apple.com's avatar
darin@apple.com committed
728
    m_frame->selection()->setCaretBlinkingSuspended(false);
ap's avatar
ap committed
729
    m_mousePressed = false;
730
    m_capturesDragging = false;
bolsinga@apple.com's avatar
bolsinga@apple.com committed
731
#if ENABLE(DRAG_SUPPORT)
732
    m_mouseDownMayStartDrag = false;
bolsinga@apple.com's avatar
bolsinga@apple.com committed
733
#endif
734 735 736
    m_mouseDownMayStartSelect = false;
    m_mouseDownMayStartAutoscroll = false;
    m_mouseDownWasInSubframe = false;
darin's avatar
darin committed
737
  
aroben's avatar
aroben committed
738 739
    bool handled = false;

740 741 742 743
    // Clear the selection if the mouse didn't move after the last mouse
    // press and it's not a context menu click.  We do this so when clicking
    // on the selection, the selection goes away.  However, if we are
    // editing, place the caret.
darin's avatar
darin committed
744
    if (m_mouseDownWasSingleClickInSelection && !m_beganSelectingText
bolsinga@apple.com's avatar
bolsinga@apple.com committed
745
#if ENABLE(DRAG_SUPPORT)
darin's avatar
darin committed
746
            && m_dragStartPos == event.event().pos()
bolsinga@apple.com's avatar
bolsinga@apple.com committed
747
#endif
748 749
            && m_frame->selection()->isRange()
            && event.event().button() != RightButton) {
750
        VisibleSelection newSelection;
751
        Node* node = targetNode(event);
752
        bool caretBrowsing = m_frame->settings()->caretBrowsingEnabled();
753
        if (node && (caretBrowsing || node->rendererIsEditable()) && node->renderer()) {
754
            VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint());
755
            newSelection = VisibleSelection(pos);
darin's avatar
darin committed
756
        }
757 758

        setSelectionIfNeeded(m_frame->selection(), newSelection);
aroben's avatar
aroben committed
759 760

        handled = true;
darin's avatar
darin committed
761 762
    }

763
    m_frame->selection()->notifyRendererOfSelectionChange(true);
darin's avatar
darin committed
764

darin@apple.com's avatar
darin@apple.com committed
765
    m_frame->selection()->selectFrameElementInParentIfFullySelected();
aroben's avatar
aroben committed
766 767

    return handled;
darin's avatar
darin committed
768 769 770 771
}

void EventHandler::handleAutoscroll(RenderObject* renderer)
{
772
    // We don't want to trigger the autoscroll or the panScroll if it's already active
darin's avatar
darin committed
773
    if (m_autoscrollTimer.isActive())
774 775
        return;     

darin's avatar
darin committed
776
    setAutoscrollRenderer(renderer);
777

778
#if ENABLE(PAN_SCROLLING)
779 780
    if (m_panScrollInProgress) {
        m_panScrollStartPos = currentMousePosition();
781 782 783 784 785 786
        if (FrameView* view = m_frame->view())
            view->addPanScrollIcon(m_panScrollStartPos);
        // If we're not in the top frame we notify it that we doing a panScroll.
        if (Page* page = m_frame->page()) {
            Frame* mainFrame = page->mainFrame();
            if (m_frame != mainFrame)
787
                mainFrame->eventHandler()->m_panScrollInProgress = true;
788
        }
789 790 791
    }
#endif

darin's avatar
darin committed
792 793 794 795 796
    startAutoscrollTimer();
}

void EventHandler::autoscrollTimerFired(Timer<EventHandler>*)
{
797
    RenderObject* r = autoscrollRenderer();
798
    if (!r || !r->isBox()) {
darin's avatar
darin committed
799 800 801
        stopAutoscrollTimer();
        return;
    }
802 803 804 805 806 807

    if (m_autoscrollInProgress) {
        if (!m_mousePressed) {
            stopAutoscrollTimer();
            return;
        }
808
        toRenderBox(r)->autoscroll();
809 810
    } else {
        // we verify that the main frame hasn't received the order to stop the panScroll
811
        if (Page* page = m_frame->page()) {