EventHandler.cpp 90 KB
Newer Older
darin's avatar
darin committed
1
/*
2
 * Copyright (C) 2006, 2007, 2008, 2009 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"
mjs's avatar
mjs committed
32
#include "ChromeClient.h"
darin's avatar
darin committed
33 34
#include "Cursor.h"
#include "Document.h"
35
#include "DragController.h"
bdakin's avatar
bdakin committed
36
#include "Editor.h"
darin's avatar
darin committed
37
#include "EventNames.h"
ddkilzer's avatar
ddkilzer committed
38
#include "FloatPoint.h"
39
#include "FloatRect.h"
adele's avatar
adele committed
40
#include "FocusController.h"
darin's avatar
darin committed
41
#include "Frame.h"
antti's avatar
antti committed
42
#include "FrameLoader.h"
darin's avatar
darin committed
43 44 45
#include "FrameTree.h"
#include "FrameView.h"
#include "HTMLFrameElementBase.h"
46
#include "HTMLFrameSetElement.h"
darin's avatar
darin committed
47 48
#include "HTMLInputElement.h"
#include "HTMLNames.h"
49 50
#include "HitTestRequest.h"
#include "HitTestResult.h"
51
#include "Image.h"
52
#include "InspectorController.h"
darin's avatar
darin committed
53 54 55
#include "KeyboardEvent.h"
#include "MouseEvent.h"
#include "MouseEventWithHitTestResults.h"
adele's avatar
adele committed
56
#include "Page.h"
adele's avatar
adele committed
57
#include "PlatformKeyboardEvent.h"
darin's avatar
darin committed
58
#include "PlatformWheelEvent.h"
59
#include "RenderFrameSet.h"
60
#include "RenderTextControlSingleLine.h"
eric@webkit.org's avatar
eric@webkit.org committed
61
#include "RenderView.h"
62
#include "RenderWidget.h"
63
#include "Scrollbar.h"
darin's avatar
darin committed
64 65
#include "SelectionController.h"
#include "Settings.h"
darin's avatar
darin committed
66
#include "TextEvent.h"
67
#include "htmlediting.h" // for comparePositions()
68
#include <wtf/StdLibExtras.h>
darin's avatar
darin committed
69

mjs's avatar
mjs committed
70
#if ENABLE(SVG)
weinig's avatar
weinig committed
71
#include "SVGDocument.h"
72
#include "SVGElementInstance.h"
darin's avatar
darin committed
73
#include "SVGNames.h"
74
#include "SVGUseElement.h"
darin's avatar
darin committed
75 76 77 78 79 80
#endif

namespace WebCore {

using namespace HTMLNames;

aliceli1's avatar
aliceli1 committed
81 82 83
// 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
84 85 86 87
const int LinkDragHysteresis = 40;
const int ImageDragHysteresis = 5;
const int TextDragHysteresis = 3;
const int GeneralDragHysteresis = 3;
aliceli1's avatar
aliceli1 committed
88

oliver's avatar
oliver committed
89 90 91 92
// 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
93
#if ENABLE(SVG)
darin's avatar
darin committed
94 95 96
using namespace SVGNames;
#endif

97 98
// 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
99

100 101
static Frame* subframeForTargetNode(Node*);
static Frame* subframeForHitTestResult(const MouseEventWithHitTestResults&);
ap's avatar
ap committed
102

103
static inline void scrollAndAcceptEvent(float delta, ScrollDirection positiveDirection, ScrollDirection negativeDirection, PlatformWheelEvent& e, Node* node)
104
{
105
    if (!delta)
106
        return;
107 108 109 110
        
    // Find the nearest enclosing box.
    RenderBox* enclosingBox = node->renderer()->enclosingBox();

111
    if (e.granularity() == ScrollByPageWheelEvent) {
112
        if (enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPage, 1))
113
            e.accept();
114 115 116
        return;
    } 
    float pixelsToScroll = delta > 0 ? delta : -delta;
117
    if (enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, pixelsToScroll))
118
        e.accept();
119 120
}

darin@apple.com's avatar
darin@apple.com committed
121 122 123 124 125 126 127 128 129 130 131 132 133 134
#if !PLATFORM(MAC)

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

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

#endif

darin's avatar
darin committed
135 136 137
EventHandler::EventHandler(Frame* frame)
    : m_frame(frame)
    , m_mousePressed(false)
138
    , m_capturesDragging(false)
darin's avatar
darin committed
139 140 141
    , m_mouseDownMayStartSelect(false)
    , m_mouseDownMayStartDrag(false)
    , m_mouseDownWasSingleClickInSelection(false)
darin's avatar
darin committed
142
    , m_beganSelectingText(false)
143
    , m_panScrollInProgress(false)
darin's avatar
darin committed
144 145 146
    , m_hoverTimer(this, &EventHandler::hoverTimerFired)
    , m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired)
    , m_autoscrollRenderer(0)
147
    , m_autoscrollInProgress(false)
darin's avatar
darin committed
148
    , m_mouseDownMayStartAutoscroll(false)
darin's avatar
darin committed
149
    , m_mouseDownWasInSubframe(false)
weinig's avatar
weinig committed
150 151 152
#if ENABLE(SVG)
    , m_svgPan(false)
#endif
darin's avatar
darin committed
153
    , m_resizeLayer(0)
adele's avatar
adele committed
154
    , m_capturingMouseEventsNode(0)
darin's avatar
darin committed
155
    , m_clickCount(0)
aliceli1's avatar
aliceli1 committed
156
    , m_mouseDownTimestamp(0)
andersca@apple.com's avatar
andersca@apple.com committed
157 158
    , m_useLatchedWheelEventNode(false)
    , m_widgetIsLatched(false)
darin's avatar
darin committed
159 160 161 162 163 164 165 166 167 168 169
#if PLATFORM(MAC)
    , m_mouseDownView(nil)
    , m_sendingEventToSubview(false)
    , m_activationEventNumber(0)
#endif
{
}

EventHandler::~EventHandler()
{
}
oliver's avatar
 
oliver committed
170 171 172
    
EventHandler::EventHandlerDragState& EventHandler::dragState()
{
173
    DEFINE_STATIC_LOCAL(EventHandlerDragState, state, ());
oliver's avatar
 
oliver committed
174 175 176
    return state;
}
    
darin's avatar
darin committed
177 178 179 180 181 182
void EventHandler::clear()
{
    m_hoverTimer.stop();
    m_resizeLayer = 0;
    m_nodeUnderMouse = 0;
    m_lastNodeUnderMouse = 0;
183 184 185 186
#if ENABLE(SVG)
    m_instanceUnderMouse = 0;
    m_lastInstanceUnderMouse = 0;
#endif
darin's avatar
darin committed
187 188 189 190 191 192 193 194 195
    m_lastMouseMoveEventSubframe = 0;
    m_lastScrollbarUnderMouse = 0;
    m_clickCount = 0;
    m_clickNode = 0;
    m_frameSetBeingResized = 0;
    m_dragTarget = 0;
    m_currentMousePosition = IntPoint();
    m_mousePressNode = 0;
    m_mousePressed = false;
196
    m_capturesDragging = false;
197
    m_capturingMouseEventsNode = 0;
andersca@apple.com's avatar
andersca@apple.com committed
198
    m_latchedWheelEventNode = 0;
darin's avatar
darin committed
199 200
}

201
void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
darin's avatar
darin committed
202
{
203
    Node* innerNode = result.targetNode();
204
    VisibleSelection newSelection;
darin's avatar
darin committed
205

adele's avatar
adele committed
206
    if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
207
        VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
darin's avatar
darin committed
208
        if (pos.isNotNull()) {
209
            newSelection = VisibleSelection(pos);
darin's avatar
darin committed
210 211 212
            newSelection.expandUsingGranularity(WordGranularity);
        }
    
213 214 215
        if (newSelection.isRange()) {
            m_frame->setSelectionGranularity(WordGranularity);
            m_beganSelectingText = true;
216 217
            if (result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled()) 
                newSelection.appendTrailingWhitespace();            
218 219 220
        }
        
        if (m_frame->shouldChangeSelection(newSelection))
darin@apple.com's avatar
darin@apple.com committed
221
            m_frame->selection()->setSelection(newSelection);
darin's avatar
darin committed
222 223 224
    }
}

mitz@apple.com's avatar
mitz@apple.com committed
225 226 227 228 229 230 231 232
void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
{
    if (!result.hitTestResult().isLiveLink())
        return selectClosestWordFromMouseEvent(result);

    Node* innerNode = result.targetNode();

    if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
233
        VisibleSelection newSelection;
mitz@apple.com's avatar
mitz@apple.com committed
234 235 236
        Element* URLElement = result.hitTestResult().URLElement();
        VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
        if (pos.isNotNull() && pos.deepEquivalent().node()->isDescendantOf(URLElement))
237
            newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
mitz@apple.com's avatar
mitz@apple.com committed
238 239 240 241 242 243 244
    
        if (newSelection.isRange()) {
            m_frame->setSelectionGranularity(WordGranularity);
            m_beganSelectingText = true;
        }

        if (m_frame->shouldChangeSelection(newSelection))
darin@apple.com's avatar
darin@apple.com committed
245
            m_frame->selection()->setSelection(newSelection);
mitz@apple.com's avatar
mitz@apple.com committed
246 247 248
    }
}

aroben's avatar
aroben committed
249
bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
darin's avatar
darin committed
250
{
aroben's avatar
aroben committed
251 252 253
    if (event.event().button() != LeftButton)
        return false;

darin@apple.com's avatar
darin@apple.com committed
254
    if (m_frame->selection()->isRange())
aroben's avatar
aroben committed
255 256 257 258 259 260 261
        // 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
262
        selectClosestWordFromMouseEvent(event);
aroben's avatar
aroben committed
263 264

    return true;
darin's avatar
darin committed
265 266
}

aroben's avatar
aroben committed
267
bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
darin's avatar
darin committed
268
{
aroben's avatar
aroben committed
269 270
    if (event.event().button() != LeftButton)
        return false;
darin's avatar
darin committed
271
    
aroben's avatar
aroben committed
272
    Node* innerNode = event.targetNode();
adele's avatar
adele committed
273
    if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
aroben's avatar
aroben committed
274 275
        return false;

276
    VisibleSelection newSelection;
277
    VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
aroben's avatar
aroben committed
278
    if (pos.isNotNull()) {
279
        newSelection = VisibleSelection(pos);
aroben's avatar
aroben committed
280
        newSelection.expandUsingGranularity(ParagraphGranularity);
darin's avatar
darin committed
281
    }
aroben's avatar
aroben committed
282 283 284 285 286 287
    if (newSelection.isRange()) {
        m_frame->setSelectionGranularity(ParagraphGranularity);
        m_beganSelectingText = true;
    }
    
    if (m_frame->shouldChangeSelection(newSelection))
darin@apple.com's avatar
darin@apple.com committed
288
        m_frame->selection()->setSelection(newSelection);
aroben's avatar
aroben committed
289 290

    return true;
darin's avatar
darin committed
291 292
}

aroben's avatar
aroben committed
293
bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
darin's avatar
darin committed
294
{
aroben's avatar
aroben committed
295
    Node* innerNode = event.targetNode();
adele's avatar
adele committed
296
    if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
aroben's avatar
aroben committed
297
        return false;
darin's avatar
darin committed
298

aroben's avatar
aroben committed
299 300
    // 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
301

aroben's avatar
aroben committed
302 303
    // Don't restart the selection when the mouse is pressed on an
    // existing selection so we can allow for text dragging.
304 305 306 307 308 309
    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
310
    }
aroben's avatar
aroben committed
311

312
    VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint()));
aroben's avatar
aroben committed
313
    if (visiblePos.isNull())
ap@webkit.org's avatar
ap@webkit.org committed
314
        visiblePos = VisiblePosition(innerNode, 0, DOWNSTREAM);
aroben's avatar
aroben committed
315 316
    Position pos = visiblePos.deepEquivalent();
    
317
    VisibleSelection newSelection = m_frame->selection()->selection();
aroben's avatar
aroben committed
318
    if (extendSelection && newSelection.isCaretOrRange()) {
darin@apple.com's avatar
darin@apple.com committed
319
        m_frame->selection()->setLastChangeWasHorizontalExtension(false);
aroben's avatar
aroben committed
320 321 322 323 324
        
        // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection 
        // was created right-to-left
        Position start = newSelection.start();
        Position end = newSelection.end();
325
        if (comparePositions(pos, start) <= 0)
326
            newSelection = VisibleSelection(pos, end);
aroben's avatar
aroben committed
327
        else
328
            newSelection = VisibleSelection(start, pos);
aroben's avatar
aroben committed
329 330 331 332 333

        if (m_frame->selectionGranularity() != CharacterGranularity)
            newSelection.expandUsingGranularity(m_frame->selectionGranularity());
        m_beganSelectingText = true;
    } else {
334
        newSelection = VisibleSelection(visiblePos);
aroben's avatar
aroben committed
335
        m_frame->setSelectionGranularity(CharacterGranularity);
darin's avatar
darin committed
336
    }
aroben's avatar
aroben committed
337 338
    
    if (m_frame->shouldChangeSelection(newSelection))
darin@apple.com's avatar
darin@apple.com committed
339
        m_frame->selection()->setSelection(newSelection);
aroben's avatar
aroben committed
340 341

    return true;
darin's avatar
darin committed
342 343
}

aroben's avatar
aroben committed
344
bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
darin's avatar
darin committed
345
{
346 347 348
    // Reset drag state.
    dragState().m_dragSrc = 0;

darin's avatar
darin committed
349 350 351 352 353 354 355 356 357
    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.
    m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode());
    
    // Careful that the drag starting logic stays in sync with eventMayStartDrag()
    m_mouseDownMayStartDrag = singleClick;

darin's avatar
darin committed
358 359
    m_mouseDownWasSingleClickInSelection = false;

360 361
    m_mouseDown = event.event();

362
    if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
aroben's avatar
aroben committed
363
        return true;
darin's avatar
darin committed
364

weinig's avatar
weinig committed
365 366 367 368 369 370 371 372 373 374 375
#if ENABLE(SVG)
    if (m_frame->document()->isSVGDocument() &&
       static_cast<SVGDocument*>(m_frame->document())->zoomAndPanEnabled()) {
        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
376 377 378 379 380 381 382 383 384 385
    // 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();

    Node* innerNode = event.targetNode();

    m_mousePressNode = innerNode;
    m_dragStartPos = event.event().pos();

aroben's avatar
aroben committed
386
    bool swallowEvent = false;
ap@webkit.org's avatar
ap@webkit.org committed
387 388 389 390 391 392 393 394 395 396
    m_frame->selection()->setCaretBlinkingSuspended(true);
    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
397
    
398 399
    m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect || 
        (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled(true));
aroben's avatar
aroben committed
400

401
    return swallowEvent;
darin's avatar
darin committed
402 403
}

404
bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
darin's avatar
darin committed
405 406
{
    if (handleDrag(event))
aroben's avatar
aroben committed
407
        return true;
darin's avatar
darin committed
408

ap's avatar
ap committed
409
    if (!m_mousePressed)
aroben's avatar
aroben committed
410
        return false;
darin's avatar
darin committed
411

darin's avatar
darin committed
412 413
    Node* targetNode = event.targetNode();
    if (event.event().button() != LeftButton || !targetNode || !targetNode->renderer())
aroben's avatar
aroben committed
414
        return false;
darin's avatar
darin committed
415 416 417 418 419 420 421

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

    m_mouseDownMayStartDrag = false;

422
    if (m_mouseDownMayStartAutoscroll && !m_panScrollInProgress) {            
darin's avatar
darin committed
423 424
        // If the selection is contained in a layer that can scroll, that layer should handle the autoscroll
        // Otherwise, let the bridge handle it so the view can scroll itself.
darin's avatar
darin committed
425
        RenderObject* renderer = targetNode->renderer();
426
        while (renderer && (!renderer->isBox() || !toRenderBox(renderer)->canBeProgramaticallyScrolled(false))) {
427 428 429 430 431 432
            if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement())
                renderer = renderer->document()->ownerElement()->renderer();
            else
                renderer = renderer->parent();
        }
        
433 434
        if (renderer) {
            m_autoscrollInProgress = true;
darin's avatar
darin committed
435
            handleAutoscroll(renderer);
436
        }
437 438
        
        m_mouseDownMayStartAutoscroll = false;
darin's avatar
darin committed
439 440
    }
    
darin's avatar
darin committed
441
    updateSelectionForMouseDrag(targetNode, event.localPoint());
aroben's avatar
aroben committed
442
    return true;
darin's avatar
darin committed
443
}
oliver's avatar
 
oliver committed
444 445 446 447 448 449 450
    
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
    
451 452 453 454
    if (!m_frame->contentRenderer() || !m_frame->contentRenderer()->hasLayer())
        return false;

    if (event.button() != LeftButton || event.clickCount() != 1)
oliver's avatar
 
oliver committed
455 456 457 458 459 460 461
        return false;
    
    bool DHTMLFlag;
    bool UAFlag;
    allowDHTMLDrag(DHTMLFlag, UAFlag);
    if (!DHTMLFlag && !UAFlag)
        return false;
462 463 464 465 466

    FrameView* view = m_frame->view();
    if (!view)
        return false;

467
    HitTestRequest request(HitTestRequest::ReadOnly);
468
    HitTestResult result(view->windowToContents(event.pos()));
eric@webkit.org's avatar
eric@webkit.org committed
469
    m_frame->contentRenderer()->layer()->hitTest(request, result);
oliver's avatar
 
oliver committed
470
    bool srcIsDHTML;
471
    return result.innerNode() && result.innerNode()->renderer()->draggableNode(DHTMLFlag, UAFlag, result.point().x(), result.point().y(), srcIsDHTML);
oliver's avatar
 
oliver committed
472
}
darin's avatar
darin committed
473

darin's avatar
darin committed
474 475 476 477 478
void EventHandler::updateSelectionForMouseDrag()
{
    FrameView* view = m_frame->view();
    if (!view)
        return;
479
    RenderView* renderer = m_frame->contentRenderer();
darin's avatar
darin committed
480 481 482 483 484 485
    if (!renderer)
        return;
    RenderLayer* layer = renderer->layer();
    if (!layer)
        return;

486 487 488
    HitTestRequest request(HitTestRequest::ReadOnly |
                           HitTestRequest::Active |
                           HitTestRequest::MouseMove);
darin's avatar
darin committed
489
    HitTestResult result(view->windowToContents(m_currentMousePosition));
490
    layer->hitTest(request, result);
darin's avatar
darin committed
491 492 493 494
    updateSelectionForMouseDrag(result.innerNode(), result.localPoint());
}

void EventHandler::updateSelectionForMouseDrag(Node* targetNode, const IntPoint& localPoint)
darin's avatar
darin committed
495
{
darin's avatar
darin committed
496 497 498 499 500 501 502 503 504
    if (!m_mouseDownMayStartSelect)
        return;

    if (!targetNode)
        return;

    RenderObject* targetRenderer = targetNode->renderer();
    if (!targetRenderer)
        return;
adele's avatar
adele committed
505 506
        
    if (!canMouseDragExtendSelect(targetNode))
darin's avatar
darin committed
507 508 509 510
        return;

    VisiblePosition targetPosition(targetRenderer->positionForPoint(localPoint));

darin's avatar
darin committed
511
    // Don't modify the selection if we're not on a node.
darin's avatar
darin committed
512
    if (targetPosition.isNull())
darin's avatar
darin committed
513 514 515 516
        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.
517
    VisibleSelection newSelection = m_frame->selection()->selection();
darin's avatar
darin committed
518 519 520 521 522 523 524 525 526 527 528

#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?
    if (Node* selectionBaseNode = newSelection.base().node())
        if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
            if (selectionBaseRenderer->isSVGText())
                if (targetNode->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
                    return;
#endif

darin's avatar
darin committed
529 530
    if (!m_beganSelectingText) {
        m_beganSelectingText = true;
531
        newSelection = VisibleSelection(targetPosition);
darin's avatar
darin committed
532 533
    }

darin's avatar
darin committed
534
    newSelection.setExtent(targetPosition);
darin's avatar
darin committed
535 536 537
    if (m_frame->selectionGranularity() != CharacterGranularity)
        newSelection.expandUsingGranularity(m_frame->selectionGranularity());

darin's avatar
darin committed
538
    if (m_frame->shouldChangeSelection(newSelection)) {
darin@apple.com's avatar
darin@apple.com committed
539 540
        m_frame->selection()->setLastChangeWasHorizontalExtension(false);
        m_frame->selection()->setSelection(newSelection);
darin's avatar
darin committed
541
    }
darin's avatar
darin committed
542
}
543 544 545 546 547 548 549 550 551 552 553 554 555
    
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
556

aroben's avatar
aroben committed
557
bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
darin's avatar
darin committed
558
{
559 560
    if (m_autoscrollInProgress)
        stopAutoscrollTimer();
darin's avatar
darin committed
561 562

    if (handleMouseUp(event))
aroben's avatar
aroben committed
563
        return true;
darin's avatar
darin committed
564 565 566

    // Used to prevent mouseMoveEvent from initiating a drag before
    // the mouse is pressed again.
darin@apple.com's avatar
darin@apple.com committed
567
    m_frame->selection()->setCaretBlinkingSuspended(false);
ap's avatar
ap committed
568
    m_mousePressed = false;
569
    m_capturesDragging = false;
570 571 572 573
    m_mouseDownMayStartDrag = false;
    m_mouseDownMayStartSelect = false;
    m_mouseDownMayStartAutoscroll = false;
    m_mouseDownWasInSubframe = false;
darin's avatar
darin committed
574
  
aroben's avatar
aroben committed
575 576
    bool handled = false;

577 578 579 580
    // 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
581
    if (m_mouseDownWasSingleClickInSelection && !m_beganSelectingText
darin's avatar
darin committed
582
            && m_dragStartPos == event.event().pos()
583 584
            && m_frame->selection()->isRange()
            && event.event().button() != RightButton) {
585
        VisibleSelection newSelection;
darin's avatar
darin committed
586
        Node *node = event.targetNode();
587 588
        bool caretBrowsing = m_frame->settings()->caretBrowsingEnabled();
        if (node && (caretBrowsing || node->isContentEditable()) && node->renderer()) {
589
            VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint());
590
            newSelection = VisibleSelection(pos);
darin's avatar
darin committed
591 592
        }
        if (m_frame->shouldChangeSelection(newSelection))
darin@apple.com's avatar
darin@apple.com committed
593
            m_frame->selection()->setSelection(newSelection);
aroben's avatar
aroben committed
594 595

        handled = true;
darin's avatar
darin committed
596 597 598 599
    }

    m_frame->notifyRendererOfSelectionChange(true);

darin@apple.com's avatar
darin@apple.com committed
600
    m_frame->selection()->selectFrameElementInParentIfFullySelected();
aroben's avatar
aroben committed
601 602

    return handled;
darin's avatar
darin committed
603 604 605 606
}

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

darin's avatar
darin committed
611
    setAutoscrollRenderer(renderer);
612

613
#if ENABLE(PAN_SCROLLING)
614 615
    if (m_panScrollInProgress) {
        m_panScrollStartPos = currentMousePosition();
616 617 618 619 620 621 622 623
        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)
                mainFrame->eventHandler()->setPanScrollInProgress(true);
        }
624 625 626
    }
#endif

darin's avatar
darin committed
627 628 629 630 631
    startAutoscrollTimer();
}

void EventHandler::autoscrollTimerFired(Timer<EventHandler>*)
{
632
    RenderObject* r = autoscrollRenderer();
633
    if (!r || !r->isBox()) {
darin's avatar
darin committed
634 635 636
        stopAutoscrollTimer();
        return;
    }
637 638 639 640 641 642

    if (m_autoscrollInProgress) {
        if (!m_mousePressed) {
            stopAutoscrollTimer();
            return;
        }
643
        toRenderBox(r)->autoscroll();
644 645
    } else {
        // we verify that the main frame hasn't received the order to stop the panScroll
646 647 648 649 650
        if (Page* page = m_frame->page()) {
            if (!page->mainFrame()->eventHandler()->panScrollInProgress()) {
                stopAutoscrollTimer();
                return;
            }
651
        }
652
#if ENABLE(PAN_SCROLLING)
653
        setPanScrollCursor();
hyatt@apple.com's avatar
hyatt@apple.com committed
654
        toRenderBox(r)->panScroll(m_panScrollStartPos);
655 656
#endif
    }
darin's avatar
darin committed
657 658
}

659
#if ENABLE(PAN_SCROLLING)
660

661 662
void EventHandler::setPanScrollCursor()
{
663 664 665 666
    FrameView* view = m_frame->view();
    if (!view)
        return;

667 668
    // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll
    // So we don't want to change the cursor over this area
jberlin@apple.com's avatar
jberlin@apple.com committed
669 670 671 672
    bool east = m_panScrollStartPos.x() < (m_currentMousePosition.x() - ScrollView::noPanScrollRadius);
    bool west = m_panScrollStartPos.x() > (m_currentMousePosition.x() + ScrollView::noPanScrollRadius);
    bool north = m_panScrollStartPos.y() > (m_currentMousePosition.y() + ScrollView::noPanScrollRadius);
    bool south = m_panScrollStartPos.y() < (m_currentMousePosition.y() - ScrollView::noPanScrollRadius);
673 674 675
         
    if (north) {
        if (east)
676
            view->setCursor(northEastPanningCursor());
677
        else if (west)
678
            view->setCursor(northWestPanningCursor());
679
        else
680
            view->setCursor(northPanningCursor());
681 682
    } else if (south) {
        if (east)
683
            view->setCursor(southEastPanningCursor());
684
        else if (west)
685
            view->setCursor(southWestPanningCursor());
686
        else
687
            view->setCursor(southPanningCursor());
688
    } else if (east)
689
        view->setCursor(eastPanningCursor());
690
    else if (west)
691
        view->setCursor(westPanningCursor());
692
    else
693
        view->setCursor(middlePanningCursor());
694
}
695

696
#endif  // ENABLE(PAN_SCROLLING)
697

darin's avatar
darin committed
698 699 700 701 702
RenderObject* EventHandler::autoscrollRenderer() const
{
    return m_autoscrollRenderer;
}

703 704 705 706 707 708 709 710 711 712
void EventHandler::updateAutoscrollRenderer()
{
    if (!m_autoscrollRenderer)
        return;

    HitTestResult hitTest = hitTestResultAtPoint(m_panScrollStartPos, true);

    if (Node* nodeAtPoint = hitTest.innerNode())
        m_autoscrollRenderer = nodeAtPoint->renderer();

713
    while (m_autoscrollRenderer && (!m_autoscrollRenderer->isBox() || !toRenderBox(m_autoscrollRenderer)->canBeProgramaticallyScrolled(false)))
714 715 716
        m_autoscrollRenderer = m_autoscrollRenderer->parent();
}

darin's avatar
darin committed
717 718 719 720 721
void EventHandler::setAutoscrollRenderer(RenderObject* renderer)
{
    m_autoscrollRenderer = renderer;
}

722 723
void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const
{
724 725 726 727
    flagDHTML = false;
    flagUA = false;

    if (!m_frame)
728
        return;
729 730 731 732 733 734 735 736 737 738

    Page* page = m_frame->page();
    if (!page)
        return;

    FrameView* view = m_frame->view();
    if (!view)
        return;

    unsigned mask = page->dragController()->delegateDragSourceAction(view->contentsToWindow(m_mouseDownPos));
739 740 741 742
    flagDHTML = (mask & DragSourceActionDHTML) != DragSourceActionNone;
    flagUA = ((mask & DragSourceActionImage) || (mask & DragSourceActionLink) || (mask & DragSourceActionSelection));
}
    
743
HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool allowShadowContent, bool ignoreClipping, HitTestScrollbars testScrollbars)
darin's avatar
darin committed
744 745
{
    HitTestResult result(point);
eric@webkit.org's avatar
eric@webkit.org committed
746
    if (!m_frame->contentRenderer())
darin's avatar
darin committed
747
        return result;
748 749 750 751
    int hitType = HitTestRequest::ReadOnly | HitTestRequest::Active;
    if (ignoreClipping)
        hitType |= HitTestRequest::IgnoreClipping;
    m_frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), result);
darin's avatar
darin committed
752 753 754

    while (true) {
        Node* n = result.innerNode();
755
        if (!result.isOverWidget() || !n || !n->renderer() || !n->renderer()->isWidget())
darin's avatar
darin committed
756
            break;
757 758
        RenderWidget* renderWidget = static_cast<RenderWidget*>(n->renderer());
        Widget* widget = renderWidget->widget();
darin's avatar
darin committed
759 760 761
        if (!widget || !widget->isFrameView())
            break;
        Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame();
eric@webkit.org's avatar
eric@webkit.org committed
762
        if (!frame || !frame->contentRenderer())
darin's avatar
darin committed
763 764
            break;
        FrameView* view = static_cast<FrameView*>(widget);
765 766
        IntPoint widgetPoint(result.localPoint().x() + view->scrollX() - renderWidget->borderLeft() - renderWidget->paddingLeft(), 
            result.localPoint().y() + view->scrollY() - renderWidget->borderTop() - renderWidget->paddingTop());
darin's avatar
darin committed
767
        HitTestResult widgetHitTestResult(widgetPoint);
768
        frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), widgetHitTestResult);
darin's avatar
darin committed
769
        result = widgetHitTestResult;
770 771

        if (testScrollbars == ShouldHitTestScrollbars) {
772
            Scrollbar* eventScrollbar = view->scrollbarAtPoint(point);
773 774 775
            if (eventScrollbar)
                result.setScrollbar(eventScrollbar);
        }
darin's avatar
darin committed
776
    }
777 778 779 780
    
    // If our HitTestResult is not visible, then we started hit testing too far down the frame chain. 
    // Another hit test at the main frame level should get us the correct visible result.
    Frame* resultFrame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : 0;
781 782 783 784 785 786 787 788 789 790 791
    if (Page* page = m_frame->page()) {
        Frame* mainFrame = page->mainFrame();
        if (m_frame != mainFrame && resultFrame && resultFrame != mainFrame && !resultFrame->editor()->insideVisibleArea(result.point())) {
            FrameView* resultView = resultFrame->view();
            FrameView* mainView = mainFrame->view();
            if (resultView && mainView) {
                IntPoint windowPoint = resultView->contentsToWindow(result.point());
                IntPoint mainFramePoint = mainView->windowToContents(windowPoint);
                result = mainFrame->eventHandler()->hitTestResultAtPoint(mainFramePoint, allowShadowContent, ignoreClipping);
            }
        }
792
    }
darin's avatar
darin committed
793

794 795
    if (!allowShadowContent)
        result.setToNonShadowAncestor();
darin's avatar
darin committed
796 797 798 799 800 801 802 803 804 805 806 807

    return result;
}


void EventHandler::startAutoscrollTimer()
{
    m_autoscrollTimer.startRepeating(autoscrollInterval);
}

void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed)
{
808 809 810 811 812 813 814 815 816 817
    if (m_autoscrollInProgress) {
        if (m_mouseDownWasInSubframe) {
            if (Frame* subframe = subframeForTargetNode(m_mousePressNode.get()))
                subframe->eventHandler()->stopAutoscrollTimer(rendererIsBeingDestroyed);
            return;
        }
    }

    if (autoscrollRenderer()) {
        if (!rendererIsBeingDestroyed && (m_autoscrollInProgress || m_panScrollInProgress))
818
            toRenderBox(autoscrollRenderer())->stopAutoscroll();
819
#if ENABLE(PAN_SCROLLING)
820
        if (m_panScrollInProgress) {
821 822 823 824
            if (FrameView* view = m_frame->view()) {
                view->removePanScrollIcon();
                view->setCursor(pointerCursor());
            }
825 826 827 828
        }
#endif

        setAutoscrollRenderer(0);
ap's avatar
ap committed
829 830
    }

darin's avatar
darin committed
831
    m_autoscrollTimer.stop();
832 833

    m_panScrollInProgress = false;
834 835 836 837 838 839 840 841

    // If we're not in the top frame we notify it that we are not doing a panScroll any more.
    if (Page* page = m_frame->page()) {
        Frame* mainFrame = page->mainFrame();
        if (m_frame != mainFrame)
            mainFrame->eventHandler()->setPanScrollInProgress(false);
    }

842
    m_autoscrollInProgress = false;
darin's avatar
darin committed
843 844 845 846 847 848 849 850 851 852 853 854 855 856
}

Node* EventHandler::mousePressNode() const
{
    return m_mousePressNode.get();
}

void EventHandler::setMousePressNode(PassRefPtr<Node> node)
{
    m_mousePressNode = node;
}

bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity)
{
ggaren's avatar
ggaren committed
857
    Node* node = m_frame->document()->focusedNode();
darin's avatar
darin committed
858 859 860 861
    if (!node)
        node = m_mousePressNode.get();
    
    if (node) {
862
        RenderObject* r = node->renderer();
863 864
        if (r && !r->isListBox())
            return r->enclosingBox()->scroll(direction, granularity);
darin's avatar
darin committed
865 866 867 868 869
    }

    return false;
}

870 871 872 873 874 875 876 877 878 879 880 881 882 883 884
bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity)
{
    bool handled = scrollOverflow(direction, granularity);
    if (!handled) {
        Frame* frame = m_frame;
        do {
            FrameView* view = frame->view();
            handled = view ? view->scroll(direction, granularity) : false;
            frame = frame->tree()->parent();
        } while (!handled && frame);
     }

    return handled;
}

darin's avatar
darin committed
885 886 887 888 889
IntPoint EventHandler::currentMousePosition() const
{
    return m_currentMousePosition;
}

890 891 892 893 894 895 896
Frame* subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
{
    if (!hitTestResult.isOverWidget())
        return 0;
    return subframeForTargetNode(hitTestResult.targetNode());
}

897
Frame* subframeForTargetNode(Node* node)
darin's avatar
darin committed
898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
{
    if (!node)
        return 0;

    RenderObject* renderer = node->renderer();
    if (!renderer || !renderer->isWidget())
        return 0;

    Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
    if (!widget || !widget->isFrameView())
        return 0;

    return static_cast<FrameView*>(widget)->frame();
}

static bool isSubmitImage(Node* node)
{
    return node && node->hasTagName(inputTag)
        && static_cast<HTMLInputElement*>(node)->inputType() == HTMLInputElement::IMAGE;
}

// Returns true if the node's editable block is not current focused for editing
static bool nodeIsNotBeingEdited(Node* node, Frame* frame)
{
darin@apple.com's avatar
darin@apple.com committed
922
    return frame->selection()->rootEditableElement() != node->rootEditableElement();
darin's avatar
darin committed
923 924
}

hyatt@apple.com's avatar
hyatt@apple.com committed
925
Cursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Scrollbar* scrollbar)
darin's avatar
darin committed
926 927
{
    // During selection, use an I-beam no matter what we're over.
adele's avatar
adele committed
928
    // If you're capturing mouse events for a particular node, don't treat this as a selection.
darin@apple.com's avatar
darin@apple.com committed
929
    if (m_mousePressed && m_mouseDownMayStartSelect && m_frame->selection()->isCaretOrRange() && !m_capturingMouseEventsNode)
darin's avatar
darin committed
930 931 932 933 934 935
        return iBeamCursor();

    Node* node = event.targetNode();
    RenderObject* renderer = node ? node->renderer() : 0;
    RenderStyle* style = renderer ? renderer->style() : 0;

936 937 938 939 940 941 942 943
    if (renderer && renderer->isFrameSet()) {
        RenderFrameSet* fs = static_cast<RenderFrameSet*>(renderer);
        if (fs->canResizeRow(event.localPoint()))
            return rowResizeCursor();
        if (fs->canResizeColumn(event.localPoint()))
            return columnResizeCursor();
    }

darin's avatar
darin committed
944 945 946
    if (style && style->cursors()) {
        const CursorList* cursors = style->cursors();
        for (unsigned i = 0; i < cursors->size(); ++i) {
947
            CachedImage* cimage = (*cursors)[i].cursorImage.get();