| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. | |
| 3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) | |
| 4 * | |
| 5 * Redistribution and use in source and binary forms, with or without | |
| 6 * modification, are permitted provided that the following conditions | |
| 7 * are met: | |
| 8 * 1. Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | |
| 11 * notice, this list of conditions and the following disclaimer in the | |
| 12 * documentation and/or other materials provided with the distribution. | |
| 13 * | |
| 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | |
| 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
| 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | |
| 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
| 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
| 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 25 */ | |
| 26 | |
| 27 #include "config.h" | |
| 28 #include "EventHandler.h" | |
| 29 | |
| 30 #include "AXObjectCache.h" | |
| 31 #include "CachedImage.h" | |
| 32 #include "ChromeClient.h" | |
| 33 #include "Cursor.h" | |
| 34 #include "Document.h" | |
| 35 #include "DragController.h" | |
| 36 #include "Editor.h" | |
| 37 #include "EventNames.h" | |
| 38 #include "FloatPoint.h" | |
| 39 #include "FloatRect.h" | |
| 40 #include "FocusController.h" | |
| 41 #include "Frame.h" | |
| 42 #include "FrameLoader.h" | |
| 43 #include "FrameTree.h" | |
| 44 #include "FrameView.h" | |
| 45 #include "HitTestRequest.h" | |
| 46 #include "HitTestResult.h" | |
| 47 #include "HTMLFrameSetElement.h" | |
| 48 #include "HTMLFrameElementBase.h" | |
| 49 #include "HTMLInputElement.h" | |
| 50 #include "HTMLNames.h" | |
| 51 #include "Image.h" | |
| 52 #include "KeyboardEvent.h" | |
| 53 #include "MouseEvent.h" | |
| 54 #include "MouseEventWithHitTestResults.h" | |
| 55 #include "Page.h" | |
| 56 #include "PlatformKeyboardEvent.h" | |
| 57 #include "PlatformScrollBar.h" | |
| 58 #include "PlatformWheelEvent.h" | |
| 59 #include "RenderFrameSet.h" | |
| 60 #include "RenderWidget.h" | |
| 61 #include "RenderView.h" | |
| 62 #include "SelectionController.h" | |
| 63 #include "Settings.h" | |
| 64 #include "TextEvent.h" | |
| 65 | |
| 66 #if ENABLE(SVG) | |
| 67 #include "SVGDocument.h" | |
| 68 #include "SVGNames.h" | |
| 69 #endif | |
| 70 | |
| 71 namespace WebCore { | |
| 72 | |
| 73 using namespace EventNames; | |
| 74 using namespace HTMLNames; | |
| 75 | |
| 76 // The link drag hysteresis is much larger than the others because there | |
| 77 // needs to be enough space to cancel the link press without starting a link dra
g, | |
| 78 // and because dragging links is rare. | |
| 79 const int LinkDragHysteresis = 40; | |
| 80 const int ImageDragHysteresis = 5; | |
| 81 const int TextDragHysteresis = 3; | |
| 82 const int GeneralDragHysteresis = 3; | |
| 83 | |
| 84 // Match key code of composition keydown event on windows. | |
| 85 // IE sends VK_PROCESSKEY which has value 229; | |
| 86 const int CompositionEventKeyCode = 229; | |
| 87 | |
| 88 #if ENABLE(SVG) | |
| 89 using namespace SVGNames; | |
| 90 #endif | |
| 91 | |
| 92 // When the autoscroll or the panScroll is triggered when do the scroll every 0.
05s to make it smooth | |
| 93 const double autoscrollInterval = 0.05; | |
| 94 | |
| 95 static Frame* subframeForTargetNode(Node* node); | |
| 96 | |
| 97 static inline void scrollAndAcceptEvent(float delta, ScrollDirection positiveDir
ection, ScrollDirection negativeDirection, bool pageScrollEnabled, PlatformWheel
Event& e, Node* node, float windowHeightOrWidth) | |
| 98 { | |
| 99 if (!delta) | |
| 100 return; | |
| 101 | |
| 102 float pixelsToScroll = delta > 0 ? delta : -delta; | |
| 103 if (!e.isContinuous() && !pageScrollEnabled) { | |
| 104 if (node->renderer()->scroll(delta < 0 ? negativeDirection : positiveDir
ection, ScrollByLine, pixelsToScroll)) | |
| 105 e.accept(); | |
| 106 } else { | |
| 107 if (pageScrollEnabled) | |
| 108 pixelsToScroll = windowHeightOrWidth; | |
| 109 if (node->renderer()->scroll(delta < 0 ? negativeDirection : positiveDir
ection, ScrollByPixel, pixelsToScroll)) | |
| 110 e.accept(); | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 EventHandler::EventHandler(Frame* frame) | |
| 115 : m_frame(frame) | |
| 116 , m_mousePressed(false) | |
| 117 , m_mouseDownMayStartSelect(false) | |
| 118 , m_mouseDownMayStartDrag(false) | |
| 119 , m_mouseDownWasSingleClickInSelection(false) | |
| 120 , m_beganSelectingText(false) | |
| 121 , m_panScrollInProgress(false) | |
| 122 , m_hoverTimer(this, &EventHandler::hoverTimerFired) | |
| 123 , m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired) | |
| 124 , m_autoscrollRenderer(0) | |
| 125 , m_autoscrollInProgress(false) | |
| 126 , m_mouseDownMayStartAutoscroll(false) | |
| 127 , m_mouseDownWasInSubframe(false) | |
| 128 #if ENABLE(SVG) | |
| 129 , m_svgPan(false) | |
| 130 #endif | |
| 131 , m_resizeLayer(0) | |
| 132 , m_capturingMouseEventsNode(0) | |
| 133 , m_clickCount(0) | |
| 134 , m_mouseDownTimestamp(0) | |
| 135 , m_pendingFrameUnloadEventCount(0) | |
| 136 , m_pendingFrameBeforeUnloadEventCount(0) | |
| 137 #if PLATFORM(MAC) | |
| 138 , m_mouseDownView(nil) | |
| 139 , m_sendingEventToSubview(false) | |
| 140 , m_activationEventNumber(0) | |
| 141 #endif | |
| 142 { | |
| 143 } | |
| 144 | |
| 145 EventHandler::~EventHandler() | |
| 146 { | |
| 147 } | |
| 148 | |
| 149 EventHandler::EventHandlerDragState& EventHandler::dragState() | |
| 150 { | |
| 151 static EventHandlerDragState state; | |
| 152 return state; | |
| 153 } | |
| 154 | |
| 155 void EventHandler::clear() | |
| 156 { | |
| 157 m_hoverTimer.stop(); | |
| 158 m_resizeLayer = 0; | |
| 159 m_nodeUnderMouse = 0; | |
| 160 m_lastNodeUnderMouse = 0; | |
| 161 m_lastMouseMoveEventSubframe = 0; | |
| 162 m_lastScrollbarUnderMouse = 0; | |
| 163 m_clickCount = 0; | |
| 164 m_clickNode = 0; | |
| 165 m_frameSetBeingResized = 0; | |
| 166 m_dragTarget = 0; | |
| 167 m_currentMousePosition = IntPoint(); | |
| 168 m_mousePressNode = 0; | |
| 169 m_mousePressed = false; | |
| 170 m_capturingMouseEventsNode = 0; | |
| 171 } | |
| 172 | |
| 173 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestRe
sults& result) | |
| 174 { | |
| 175 Node* innerNode = result.targetNode(); | |
| 176 Selection newSelection; | |
| 177 | |
| 178 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) { | |
| 179 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.local
Point())); | |
| 180 if (pos.isNotNull()) { | |
| 181 newSelection = Selection(pos); | |
| 182 newSelection.expandUsingGranularity(WordGranularity); | |
| 183 } | |
| 184 | |
| 185 if (newSelection.isRange()) { | |
| 186 m_frame->setSelectionGranularity(WordGranularity); | |
| 187 m_beganSelectingText = true; | |
| 188 } | |
| 189 | |
| 190 if (m_frame->shouldChangeSelection(newSelection)) | |
| 191 m_frame->selection()->setSelection(newSelection); | |
| 192 } | |
| 193 } | |
| 194 | |
| 195 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHit
TestResults& result) | |
| 196 { | |
| 197 if (!result.hitTestResult().isLiveLink()) | |
| 198 return selectClosestWordFromMouseEvent(result); | |
| 199 | |
| 200 Node* innerNode = result.targetNode(); | |
| 201 | |
| 202 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) { | |
| 203 Selection newSelection; | |
| 204 Element* URLElement = result.hitTestResult().URLElement(); | |
| 205 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.local
Point())); | |
| 206 if (pos.isNotNull() && pos.deepEquivalent().node()->isDescendantOf(URLEl
ement)) | |
| 207 newSelection = Selection::selectionFromContentsOfNode(URLElement); | |
| 208 | |
| 209 if (newSelection.isRange()) { | |
| 210 m_frame->setSelectionGranularity(WordGranularity); | |
| 211 m_beganSelectingText = true; | |
| 212 } | |
| 213 | |
| 214 if (m_frame->shouldChangeSelection(newSelection)) | |
| 215 m_frame->selection()->setSelection(newSelection); | |
| 216 } | |
| 217 } | |
| 218 | |
| 219 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestR
esults& event) | |
| 220 { | |
| 221 if (event.event().button() != LeftButton) | |
| 222 return false; | |
| 223 | |
| 224 if (m_frame->selection()->isRange()) | |
| 225 // A double-click when range is already selected | |
| 226 // should not change the selection. So, do not call | |
| 227 // selectClosestWordFromMouseEvent, but do set | |
| 228 // m_beganSelectingText to prevent handleMouseReleaseEvent | |
| 229 // from setting caret selection. | |
| 230 m_beganSelectingText = true; | |
| 231 else | |
| 232 selectClosestWordFromMouseEvent(event); | |
| 233 | |
| 234 return true; | |
| 235 } | |
| 236 | |
| 237 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestR
esults& event) | |
| 238 { | |
| 239 if (event.event().button() != LeftButton) | |
| 240 return false; | |
| 241 | |
| 242 Node* innerNode = event.targetNode(); | |
| 243 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect)) | |
| 244 return false; | |
| 245 | |
| 246 Selection newSelection; | |
| 247 VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint
())); | |
| 248 if (pos.isNotNull()) { | |
| 249 newSelection = Selection(pos); | |
| 250 newSelection.expandUsingGranularity(ParagraphGranularity); | |
| 251 } | |
| 252 if (newSelection.isRange()) { | |
| 253 m_frame->setSelectionGranularity(ParagraphGranularity); | |
| 254 m_beganSelectingText = true; | |
| 255 } | |
| 256 | |
| 257 if (m_frame->shouldChangeSelection(newSelection)) | |
| 258 m_frame->selection()->setSelection(newSelection); | |
| 259 | |
| 260 return true; | |
| 261 } | |
| 262 | |
| 263 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestR
esults& event) | |
| 264 { | |
| 265 if (event.event().button() != LeftButton) | |
| 266 return false; | |
| 267 | |
| 268 Node* innerNode = event.targetNode(); | |
| 269 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect)) | |
| 270 return false; | |
| 271 | |
| 272 // Extend the selection if the Shift key is down, unless the click is in a l
ink. | |
| 273 bool extendSelection = event.event().shiftKey() && !event.isOverLink(); | |
| 274 | |
| 275 // Don't restart the selection when the mouse is pressed on an | |
| 276 // existing selection so we can allow for text dragging. | |
| 277 IntPoint vPoint = m_frame->view()->windowToContents(event.event().pos()); | |
| 278 if (!extendSelection && m_frame->selection()->contains(vPoint)) { | |
| 279 m_mouseDownWasSingleClickInSelection = true; | |
| 280 return false; | |
| 281 } | |
| 282 | |
| 283 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.loc
alPoint())); | |
| 284 if (visiblePos.isNull()) | |
| 285 visiblePos = VisiblePosition(innerNode, 0, DOWNSTREAM); | |
| 286 Position pos = visiblePos.deepEquivalent(); | |
| 287 | |
| 288 Selection newSelection = m_frame->selection()->selection(); | |
| 289 if (extendSelection && newSelection.isCaretOrRange()) { | |
| 290 m_frame->selection()->setLastChangeWasHorizontalExtension(false); | |
| 291 | |
| 292 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects
when selection | |
| 293 // was created right-to-left | |
| 294 Position start = newSelection.start(); | |
| 295 Position end = newSelection.end(); | |
| 296 short before = Range::compareBoundaryPoints(pos.node(), pos.offset(), st
art.node(), start.offset()); | |
| 297 if (before <= 0) | |
| 298 newSelection = Selection(pos, end); | |
| 299 else | |
| 300 newSelection = Selection(start, pos); | |
| 301 | |
| 302 if (m_frame->selectionGranularity() != CharacterGranularity) | |
| 303 newSelection.expandUsingGranularity(m_frame->selectionGranularity())
; | |
| 304 m_beganSelectingText = true; | |
| 305 } else { | |
| 306 newSelection = Selection(visiblePos); | |
| 307 m_frame->setSelectionGranularity(CharacterGranularity); | |
| 308 } | |
| 309 | |
| 310 if (m_frame->shouldChangeSelection(newSelection)) | |
| 311 m_frame->selection()->setSelection(newSelection); | |
| 312 | |
| 313 return true; | |
| 314 } | |
| 315 | |
| 316 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve
nt) | |
| 317 { | |
| 318 // Reset drag state. | |
| 319 dragState().m_dragSrc = 0; | |
| 320 | |
| 321 bool singleClick = event.event().clickCount() <= 1; | |
| 322 | |
| 323 // If we got the event back, that must mean it wasn't prevented, | |
| 324 // so it's allowed to start a drag or selection. | |
| 325 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode()); | |
| 326 | |
| 327 // Careful that the drag starting logic stays in sync with eventMayStartDrag
() | |
| 328 m_mouseDownMayStartDrag = singleClick; | |
| 329 | |
| 330 m_mouseDownWasSingleClickInSelection = false; | |
| 331 | |
| 332 if (passWidgetMouseDownEventToWidget(event)) | |
| 333 return true; | |
| 334 | |
| 335 #if ENABLE(SVG) | |
| 336 if (m_frame->document()->isSVGDocument() && | |
| 337 static_cast<SVGDocument*>(m_frame->document())->zoomAndPanEnabled()) { | |
| 338 if (event.event().shiftKey() && singleClick) { | |
| 339 m_svgPan = true; | |
| 340 static_cast<SVGDocument*>(m_frame->document())->startPan(event.event
().pos()); | |
| 341 return true; | |
| 342 } | |
| 343 } | |
| 344 #endif | |
| 345 | |
| 346 // We don't do this at the start of mouse down handling, | |
| 347 // because we don't want to do it until we know we didn't hit a widget. | |
| 348 if (singleClick) | |
| 349 focusDocumentView(); | |
| 350 | |
| 351 Node* innerNode = event.targetNode(); | |
| 352 | |
| 353 m_mousePressNode = innerNode; | |
| 354 m_dragStartPos = event.event().pos(); | |
| 355 | |
| 356 bool swallowEvent = false; | |
| 357 if (event.event().button() == LeftButton || event.event().button() == Middle
Button) { | |
| 358 m_frame->selection()->setCaretBlinkingSuspended(true); | |
| 359 m_mousePressed = true; | |
| 360 m_beganSelectingText = false; | |
| 361 | |
| 362 if (event.event().clickCount() == 2) | |
| 363 swallowEvent = handleMousePressEventDoubleClick(event); | |
| 364 else if (event.event().clickCount() >= 3) | |
| 365 swallowEvent = handleMousePressEventTripleClick(event); | |
| 366 else | |
| 367 swallowEvent = handleMousePressEventSingleClick(event); | |
| 368 } | |
| 369 | |
| 370 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect || | |
| 371 (m_mousePressNode && m_mousePressNode->renderer() && m_mousePressNode->r
enderer()->canBeProgramaticallyScrolled(true)); | |
| 372 | |
| 373 return swallowEvent; | |
| 374 } | |
| 375 | |
| 376 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e
vent) | |
| 377 { | |
| 378 if (handleDrag(event)) | |
| 379 return true; | |
| 380 | |
| 381 if (!m_mousePressed) | |
| 382 return false; | |
| 383 | |
| 384 Node* targetNode = event.targetNode(); | |
| 385 if (event.event().button() != LeftButton || !targetNode || !targetNode->rend
erer()) | |
| 386 return false; | |
| 387 | |
| 388 #if PLATFORM(MAC) // FIXME: Why does this assertion fire on other platforms? | |
| 389 ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll); | |
| 390 #endif | |
| 391 | |
| 392 m_mouseDownMayStartDrag = false; | |
| 393 | |
| 394 if (m_mouseDownMayStartAutoscroll && !m_panScrollInProgress) { | |
| 395 // If the selection is contained in a layer that can scroll, that layer
should handle the autoscroll | |
| 396 // Otherwise, let the bridge handle it so the view can scroll itself. | |
| 397 RenderObject* renderer = targetNode->renderer(); | |
| 398 while (renderer && !renderer->canBeProgramaticallyScrolled(false)) { | |
| 399 if (!renderer->parent() && renderer->node() == renderer->document()
&& renderer->document()->ownerElement()) | |
| 400 renderer = renderer->document()->ownerElement()->renderer(); | |
| 401 else | |
| 402 renderer = renderer->parent(); | |
| 403 } | |
| 404 | |
| 405 if (renderer) { | |
| 406 m_autoscrollInProgress = true; | |
| 407 handleAutoscroll(renderer); | |
| 408 } | |
| 409 | |
| 410 m_mouseDownMayStartAutoscroll = false; | |
| 411 } | |
| 412 | |
| 413 updateSelectionForMouseDrag(targetNode, event.localPoint()); | |
| 414 return true; | |
| 415 } | |
| 416 | |
| 417 bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const | |
| 418 { | |
| 419 // This is a pre-flight check of whether the event might lead to a drag bein
g started. Be careful | |
| 420 // that its logic needs to stay in sync with handleMouseMoveEvent() and the
way we setMouseDownMayStartDrag | |
| 421 // in handleMousePressEvent | |
| 422 | |
| 423 if (!m_frame->contentRenderer() || !m_frame->contentRenderer()->hasLayer() | |
| 424 || event.button() != LeftButton || event.clickCount() != 1) | |
| 425 return false; | |
| 426 | |
| 427 bool DHTMLFlag; | |
| 428 bool UAFlag; | |
| 429 allowDHTMLDrag(DHTMLFlag, UAFlag); | |
| 430 if (!DHTMLFlag && !UAFlag) | |
| 431 return false; | |
| 432 | |
| 433 HitTestRequest request(true, false); | |
| 434 HitTestResult result(m_frame->view()->windowToContents(event.pos())); | |
| 435 m_frame->contentRenderer()->layer()->hitTest(request, result); | |
| 436 bool srcIsDHTML; | |
| 437 return result.innerNode() && result.innerNode()->renderer()->draggableNode(D
HTMLFlag, UAFlag, result.point().x(), result.point().y(), srcIsDHTML); | |
| 438 } | |
| 439 | |
| 440 void EventHandler::updateSelectionForMouseDrag() | |
| 441 { | |
| 442 FrameView* view = m_frame->view(); | |
| 443 if (!view) | |
| 444 return; | |
| 445 RenderObject* renderer = m_frame->contentRenderer(); | |
| 446 if (!renderer) | |
| 447 return; | |
| 448 RenderLayer* layer = renderer->layer(); | |
| 449 if (!layer) | |
| 450 return; | |
| 451 | |
| 452 HitTestResult result(view->windowToContents(m_currentMousePosition)); | |
| 453 layer->hitTest(HitTestRequest(true, true, true), result); | |
| 454 updateSelectionForMouseDrag(result.innerNode(), result.localPoint()); | |
| 455 } | |
| 456 | |
| 457 void EventHandler::updateSelectionForMouseDrag(Node* targetNode, const IntPoint&
localPoint) | |
| 458 { | |
| 459 if (!m_mouseDownMayStartSelect) | |
| 460 return; | |
| 461 | |
| 462 if (!targetNode) | |
| 463 return; | |
| 464 | |
| 465 RenderObject* targetRenderer = targetNode->renderer(); | |
| 466 if (!targetRenderer) | |
| 467 return; | |
| 468 | |
| 469 if (!canMouseDragExtendSelect(targetNode)) | |
| 470 return; | |
| 471 | |
| 472 VisiblePosition targetPosition(targetRenderer->positionForPoint(localPoint))
; | |
| 473 | |
| 474 // Don't modify the selection if we're not on a node. | |
| 475 if (targetPosition.isNull()) | |
| 476 return; | |
| 477 | |
| 478 // Restart the selection if this is the first mouse move. This work is usual
ly | |
| 479 // done in handleMousePressEvent, but not if the mouse press was on an exist
ing selection. | |
| 480 Selection newSelection = m_frame->selection()->selection(); | |
| 481 | |
| 482 #if ENABLE(SVG) | |
| 483 // Special case to limit selection to the containing block for SVG text. | |
| 484 // FIXME: Isn't there a better non-SVG-specific way to do this? | |
| 485 if (Node* selectionBaseNode = newSelection.base().node()) | |
| 486 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer()) | |
| 487 if (selectionBaseRenderer->isSVGText()) | |
| 488 if (targetNode->renderer()->containingBlock() != selectionBaseRe
nderer->containingBlock()) | |
| 489 return; | |
| 490 #endif | |
| 491 | |
| 492 if (!m_beganSelectingText) { | |
| 493 m_beganSelectingText = true; | |
| 494 newSelection = Selection(targetPosition); | |
| 495 } | |
| 496 | |
| 497 newSelection.setExtent(targetPosition); | |
| 498 if (m_frame->selectionGranularity() != CharacterGranularity) | |
| 499 newSelection.expandUsingGranularity(m_frame->selectionGranularity()); | |
| 500 | |
| 501 if (m_frame->shouldChangeSelection(newSelection)) { | |
| 502 m_frame->selection()->setLastChangeWasHorizontalExtension(false); | |
| 503 m_frame->selection()->setSelection(newSelection); | |
| 504 } | |
| 505 } | |
| 506 | |
| 507 bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event) | |
| 508 { | |
| 509 if (eventLoopHandleMouseUp(event)) | |
| 510 return true; | |
| 511 | |
| 512 // If this was the first click in the window, we don't even want to clear th
e selection. | |
| 513 // This case occurs when the user clicks on a draggable element, since we ha
ve to process | |
| 514 // the mouse down and drag events to see if we might start a drag. For othe
r first clicks | |
| 515 // in a window, we just don't acceptFirstMouse, and the whole down-drag-up s
equence gets | |
| 516 // ignored upstream of this layer. | |
| 517 return eventActivatedView(event.event()); | |
| 518 } | |
| 519 | |
| 520 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& e
vent) | |
| 521 { | |
| 522 if (m_autoscrollInProgress) | |
| 523 stopAutoscrollTimer(); | |
| 524 | |
| 525 if (handleMouseUp(event)) | |
| 526 return true; | |
| 527 | |
| 528 // Used to prevent mouseMoveEvent from initiating a drag before | |
| 529 // the mouse is pressed again. | |
| 530 m_frame->selection()->setCaretBlinkingSuspended(false); | |
| 531 m_mousePressed = false; | |
| 532 m_mouseDownMayStartDrag = false; | |
| 533 m_mouseDownMayStartSelect = false; | |
| 534 m_mouseDownMayStartAutoscroll = false; | |
| 535 m_mouseDownWasInSubframe = false; | |
| 536 | |
| 537 bool handled = false; | |
| 538 | |
| 539 // Clear the selection if the mouse didn't move after the last mouse press. | |
| 540 // We do this so when clicking on the selection, the selection goes away. | |
| 541 // However, if we are editing, place the caret. | |
| 542 if (m_mouseDownWasSingleClickInSelection && !m_beganSelectingText | |
| 543 && m_dragStartPos == event.event().pos() | |
| 544 && m_frame->selection()->isRange()) { | |
| 545 Selection newSelection; | |
| 546 Node *node = event.targetNode(); | |
| 547 if (node && node->isContentEditable() && node->renderer()) { | |
| 548 VisiblePosition pos = node->renderer()->positionForPoint(event.local
Point()); | |
| 549 newSelection = Selection(pos); | |
| 550 } | |
| 551 if (m_frame->shouldChangeSelection(newSelection)) | |
| 552 m_frame->selection()->setSelection(newSelection); | |
| 553 | |
| 554 handled = true; | |
| 555 } | |
| 556 | |
| 557 m_frame->notifyRendererOfSelectionChange(true); | |
| 558 | |
| 559 m_frame->selection()->selectFrameElementInParentIfFullySelected(); | |
| 560 | |
| 561 return handled; | |
| 562 } | |
| 563 | |
| 564 void EventHandler::handleAutoscroll(RenderObject* renderer) | |
| 565 { | |
| 566 // We don't want to trigger the autoscroll or the panScroll if it's already
active | |
| 567 if (m_autoscrollTimer.isActive()) | |
| 568 return; | |
| 569 | |
| 570 setAutoscrollRenderer(renderer); | |
| 571 | |
| 572 #if PLATFORM(WIN) | |
| 573 if (m_panScrollInProgress) { | |
| 574 m_panScrollStartPos = currentMousePosition(); | |
| 575 m_frame->view()->printPanScrollIcon(m_panScrollStartPos); | |
| 576 // If we're not in the top frame we notify it that we are using the panS
croll | |
| 577 if (m_frame != m_frame->page()->mainFrame()) | |
| 578 m_frame->page()->mainFrame()->eventHandler()->setPanScrollInProgress
(true); | |
| 579 } | |
| 580 #endif | |
| 581 | |
| 582 startAutoscrollTimer(); | |
| 583 } | |
| 584 | |
| 585 void EventHandler::autoscrollTimerFired(Timer<EventHandler>*) | |
| 586 { | |
| 587 RenderObject* r = autoscrollRenderer(); | |
| 588 if (!r) { | |
| 589 stopAutoscrollTimer(); | |
| 590 return; | |
| 591 } | |
| 592 | |
| 593 if (m_autoscrollInProgress) { | |
| 594 if (!m_mousePressed) { | |
| 595 stopAutoscrollTimer(); | |
| 596 return; | |
| 597 } | |
| 598 r->autoscroll(); | |
| 599 } else { | |
| 600 // we verify that the main frame hasn't received the order to stop the p
anScroll | |
| 601 if (!m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress()
) { | |
| 602 stopAutoscrollTimer(); | |
| 603 return; | |
| 604 } | |
| 605 #if PLATFORM(WIN) | |
| 606 setPanScrollCursor(); | |
| 607 r->panScroll(m_panScrollStartPos); | |
| 608 #endif | |
| 609 } | |
| 610 } | |
| 611 | |
| 612 void EventHandler::setPanScrollCursor() | |
| 613 { | |
| 614 // At the original click location we draw a 4 arrowed icon. Over this icon t
here won't be any scroll | |
| 615 // So we don't want to change the cursor over this area | |
| 616 const int noScrollRadius = 9; | |
| 617 bool east = m_panScrollStartPos.x() < (m_currentMousePosition.x() - noScroll
Radius); | |
| 618 bool west = m_panScrollStartPos.x() > (m_currentMousePosition.x() + noScroll
Radius); | |
| 619 bool north = m_panScrollStartPos.y() > (m_currentMousePosition.y() + noScrol
lRadius); | |
| 620 bool south = m_panScrollStartPos.y() < (m_currentMousePosition.y() - noScrol
lRadius); | |
| 621 | |
| 622 if (north) { | |
| 623 if (east) | |
| 624 m_frame->view()->setCursor(northEastPanningCursor()); | |
| 625 else if (west) | |
| 626 m_frame->view()->setCursor(northWestPanningCursor()); | |
| 627 else | |
| 628 m_frame->view()->setCursor(northPanningCursor()); | |
| 629 } else if (south) { | |
| 630 if (east) | |
| 631 m_frame->view()->setCursor(southEastPanningCursor()); | |
| 632 else if (west) | |
| 633 m_frame->view()->setCursor(southWestPanningCursor()); | |
| 634 else | |
| 635 m_frame->view()->setCursor(southPanningCursor()); | |
| 636 } else if (east) | |
| 637 m_frame->view()->setCursor(eastPanningCursor()); | |
| 638 else if (west) | |
| 639 m_frame->view()->setCursor(westPanningCursor()); | |
| 640 else | |
| 641 m_frame->view()->setCursor(middlePanningCursor()); | |
| 642 } | |
| 643 | |
| 644 RenderObject* EventHandler::autoscrollRenderer() const | |
| 645 { | |
| 646 return m_autoscrollRenderer; | |
| 647 } | |
| 648 | |
| 649 void EventHandler::updateAutoscrollRenderer() | |
| 650 { | |
| 651 if (!m_autoscrollRenderer) | |
| 652 return; | |
| 653 | |
| 654 HitTestResult hitTest = hitTestResultAtPoint(m_panScrollStartPos, true); | |
| 655 | |
| 656 if (Node* nodeAtPoint = hitTest.innerNode()) | |
| 657 m_autoscrollRenderer = nodeAtPoint->renderer(); | |
| 658 | |
| 659 while (m_autoscrollRenderer && !m_autoscrollRenderer->canBeProgramaticallySc
rolled(false)) | |
| 660 m_autoscrollRenderer = m_autoscrollRenderer->parent(); | |
| 661 } | |
| 662 | |
| 663 void EventHandler::setAutoscrollRenderer(RenderObject* renderer) | |
| 664 { | |
| 665 m_autoscrollRenderer = renderer; | |
| 666 } | |
| 667 | |
| 668 void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const | |
| 669 { | |
| 670 if (!m_frame || !m_frame->document()) { | |
| 671 flagDHTML = false; | |
| 672 flagUA = false; | |
| 673 } | |
| 674 | |
| 675 unsigned mask = m_frame->page()->dragController()->delegateDragSourceAction(
m_frame->view()->contentsToWindow(m_mouseDownPos)); | |
| 676 flagDHTML = (mask & DragSourceActionDHTML) != DragSourceActionNone; | |
| 677 flagUA = ((mask & DragSourceActionImage) || (mask & DragSourceActionLink) ||
(mask & DragSourceActionSelection)); | |
| 678 } | |
| 679 | |
| 680 HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool all
owShadowContent) | |
| 681 { | |
| 682 HitTestResult result(point); | |
| 683 if (!m_frame->contentRenderer()) | |
| 684 return result; | |
| 685 m_frame->contentRenderer()->layer()->hitTest(HitTestRequest(true, true), res
ult); | |
| 686 | |
| 687 while (true) { | |
| 688 Node* n = result.innerNode(); | |
| 689 if (!n || !n->renderer() || !n->renderer()->isWidget()) | |
| 690 break; | |
| 691 Widget* widget = static_cast<RenderWidget*>(n->renderer())->widget(); | |
| 692 if (!widget || !widget->isFrameView()) | |
| 693 break; | |
| 694 Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame(); | |
| 695 if (!frame || !frame->contentRenderer()) | |
| 696 break; | |
| 697 FrameView* view = static_cast<FrameView*>(widget); | |
| 698 IntPoint widgetPoint(result.localPoint().x() + view->contentsX() - n->re
nderer()->borderLeft() - n->renderer()->paddingLeft(), | |
| 699 result.localPoint().y() + view->contentsY() - n->renderer()->borderT
op() - n->renderer()->paddingTop()); | |
| 700 HitTestResult widgetHitTestResult(widgetPoint); | |
| 701 frame->contentRenderer()->layer()->hitTest(HitTestRequest(true, true), w
idgetHitTestResult); | |
| 702 result = widgetHitTestResult; | |
| 703 } | |
| 704 | |
| 705 if (!allowShadowContent) | |
| 706 result.setToNonShadowAncestor(); | |
| 707 | |
| 708 return result; | |
| 709 } | |
| 710 | |
| 711 | |
| 712 void EventHandler::startAutoscrollTimer() | |
| 713 { | |
| 714 m_autoscrollTimer.startRepeating(autoscrollInterval); | |
| 715 } | |
| 716 | |
| 717 void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed) | |
| 718 { | |
| 719 if (m_autoscrollInProgress) { | |
| 720 if (m_mouseDownWasInSubframe) { | |
| 721 if (Frame* subframe = subframeForTargetNode(m_mousePressNode.get())) | |
| 722 subframe->eventHandler()->stopAutoscrollTimer(rendererIsBeingDes
troyed); | |
| 723 return; | |
| 724 } | |
| 725 } | |
| 726 | |
| 727 if (autoscrollRenderer()) { | |
| 728 if (!rendererIsBeingDestroyed && (m_autoscrollInProgress || m_panScrollI
nProgress)) | |
| 729 autoscrollRenderer()->stopAutoscroll(); | |
| 730 #if PLATFORM(WIN) | |
| 731 if (m_panScrollInProgress) { | |
| 732 m_frame->view()->removePanScrollIcon(); | |
| 733 } | |
| 734 #endif | |
| 735 | |
| 736 setAutoscrollRenderer(0); | |
| 737 } | |
| 738 | |
| 739 m_autoscrollTimer.stop(); | |
| 740 | |
| 741 m_panScrollInProgress = false; | |
| 742 // If we're not in the top frame we notify it that we are not using the panS
croll anymore | |
| 743 if (m_frame->page() && m_frame != m_frame->page()->mainFrame()) | |
| 744 m_frame->page()->mainFrame()->eventHandler()->setPanScrollInProgress
(false); | |
| 745 m_autoscrollInProgress = false; | |
| 746 } | |
| 747 | |
| 748 Node* EventHandler::mousePressNode() const | |
| 749 { | |
| 750 return m_mousePressNode.get(); | |
| 751 } | |
| 752 | |
| 753 void EventHandler::setMousePressNode(PassRefPtr<Node> node) | |
| 754 { | |
| 755 m_mousePressNode = node; | |
| 756 } | |
| 757 | |
| 758 bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity g
ranularity) | |
| 759 { | |
| 760 if (!m_frame->document()) | |
| 761 return false; | |
| 762 | |
| 763 Node* node = m_frame->document()->focusedNode(); | |
| 764 if (!node) | |
| 765 node = m_mousePressNode.get(); | |
| 766 | |
| 767 if (node) { | |
| 768 RenderObject *r = node->renderer(); | |
| 769 if (r && !r->isListBox()) | |
| 770 return r->scroll(direction, granularity); | |
| 771 } | |
| 772 | |
| 773 return false; | |
| 774 } | |
| 775 | |
| 776 IntPoint EventHandler::currentMousePosition() const | |
| 777 { | |
| 778 return m_currentMousePosition; | |
| 779 } | |
| 780 | |
| 781 Frame* subframeForTargetNode(Node* node) | |
| 782 { | |
| 783 if (!node) | |
| 784 return 0; | |
| 785 | |
| 786 RenderObject* renderer = node->renderer(); | |
| 787 if (!renderer || !renderer->isWidget()) | |
| 788 return 0; | |
| 789 | |
| 790 Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); | |
| 791 if (!widget || !widget->isFrameView()) | |
| 792 return 0; | |
| 793 | |
| 794 return static_cast<FrameView*>(widget)->frame(); | |
| 795 } | |
| 796 | |
| 797 static bool isSubmitImage(Node* node) | |
| 798 { | |
| 799 return node && node->hasTagName(inputTag) | |
| 800 && static_cast<HTMLInputElement*>(node)->inputType() == HTMLInputElement
::IMAGE; | |
| 801 } | |
| 802 | |
| 803 // Returns true if the node's editable block is not current focused for editing | |
| 804 static bool nodeIsNotBeingEdited(Node* node, Frame* frame) | |
| 805 { | |
| 806 return frame->selection()->rootEditableElement() != node->rootEditableElemen
t(); | |
| 807 } | |
| 808 | |
| 809 Cursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Pla
tformScrollbar* scrollbar) | |
| 810 { | |
| 811 // During selection, use an I-beam no matter what we're over. | |
| 812 // If you're capturing mouse events for a particular node, don't treat this
as a selection. | |
| 813 if (m_mousePressed && m_mouseDownMayStartSelect && m_frame->selection()->isC
aretOrRange() && !m_capturingMouseEventsNode) | |
| 814 return iBeamCursor(); | |
| 815 | |
| 816 Node* node = event.targetNode(); | |
| 817 RenderObject* renderer = node ? node->renderer() : 0; | |
| 818 RenderStyle* style = renderer ? renderer->style() : 0; | |
| 819 | |
| 820 if (renderer && renderer->isFrameSet()) { | |
| 821 RenderFrameSet* fs = static_cast<RenderFrameSet*>(renderer); | |
| 822 if (fs->canResizeRow(event.localPoint())) | |
| 823 return rowResizeCursor(); | |
| 824 if (fs->canResizeColumn(event.localPoint())) | |
| 825 return columnResizeCursor(); | |
| 826 } | |
| 827 | |
| 828 if (style && style->cursors()) { | |
| 829 const CursorList* cursors = style->cursors(); | |
| 830 for (unsigned i = 0; i < cursors->size(); ++i) { | |
| 831 CachedImage* cimage = (*cursors)[i].cursorImage; | |
| 832 IntPoint hotSpot = (*cursors)[i].hotSpot; | |
| 833 if (!cimage) | |
| 834 continue; | |
| 835 // Limit the size of cursors so that they cannot be used to cover UI
elements in chrome. | |
| 836 IntSize size = cimage->image()->size(); | |
| 837 if (size.width() > 128 || size.height() > 128) | |
| 838 continue; | |
| 839 // Do not let the hotspot be outside the bounds of the image. | |
| 840 if (hotSpot.x() < 0 || hotSpot.y() < 0 || hotSpot.x() > size.width()
|| hotSpot.y() > size.height()) | |
| 841 continue; | |
| 842 if (cimage->image()->isNull()) | |
| 843 break; | |
| 844 if (!cimage->errorOccurred()) | |
| 845 return Cursor(cimage->image(), hotSpot); | |
| 846 } | |
| 847 } | |
| 848 | |
| 849 switch (style ? style->cursor() : CURSOR_AUTO) { | |
| 850 case CURSOR_AUTO: { | |
| 851 bool editable = (node && node->isContentEditable()); | |
| 852 bool editableLinkEnabled = false; | |
| 853 | |
| 854 // If the link is editable, then we need to check the settings to se
e whether or not the link should be followed | |
| 855 if (editable) { | |
| 856 ASSERT(m_frame->settings()); | |
| 857 switch(m_frame->settings()->editableLinkBehavior()) { | |
| 858 default: | |
| 859 case EditableLinkDefaultBehavior: | |
| 860 case EditableLinkAlwaysLive: | |
| 861 editableLinkEnabled = true; | |
| 862 break; | |
| 863 | |
| 864 case EditableLinkNeverLive: | |
| 865 editableLinkEnabled = false; | |
| 866 break; | |
| 867 | |
| 868 case EditableLinkLiveWhenNotFocused: | |
| 869 editableLinkEnabled = nodeIsNotBeingEdited(node, m_frame
) || event.event().shiftKey(); | |
| 870 break; | |
| 871 | |
| 872 case EditableLinkOnlyLiveWithShiftKey: | |
| 873 editableLinkEnabled = event.event().shiftKey(); | |
| 874 break; | |
| 875 } | |
| 876 } | |
| 877 | |
| 878 if ((event.isOverLink() || isSubmitImage(node)) && (!editable || edi
tableLinkEnabled)) | |
| 879 return handCursor(); | |
| 880 RenderLayer* layer = renderer ? renderer->enclosingLayer() : 0; | |
| 881 bool inResizer = false; | |
| 882 if (m_frame->view() && layer && layer->isPointInResizeControl(m_fram
e->view()->windowToContents(event.event().pos()))) | |
| 883 inResizer = true; | |
| 884 if ((editable || (renderer && renderer->isText() && node->canStartSe
lection())) && !inResizer && !scrollbar) | |
| 885 return iBeamCursor(); | |
| 886 return pointerCursor(); | |
| 887 } | |
| 888 case CURSOR_CROSS: | |
| 889 return crossCursor(); | |
| 890 case CURSOR_POINTER: | |
| 891 return handCursor(); | |
| 892 case CURSOR_MOVE: | |
| 893 return moveCursor(); | |
| 894 case CURSOR_ALL_SCROLL: | |
| 895 return moveCursor(); | |
| 896 case CURSOR_E_RESIZE: | |
| 897 return eastResizeCursor(); | |
| 898 case CURSOR_W_RESIZE: | |
| 899 return westResizeCursor(); | |
| 900 case CURSOR_N_RESIZE: | |
| 901 return northResizeCursor(); | |
| 902 case CURSOR_S_RESIZE: | |
| 903 return southResizeCursor(); | |
| 904 case CURSOR_NE_RESIZE: | |
| 905 return northEastResizeCursor(); | |
| 906 case CURSOR_SW_RESIZE: | |
| 907 return southWestResizeCursor(); | |
| 908 case CURSOR_NW_RESIZE: | |
| 909 return northWestResizeCursor(); | |
| 910 case CURSOR_SE_RESIZE: | |
| 911 return southEastResizeCursor(); | |
| 912 case CURSOR_NS_RESIZE: | |
| 913 return northSouthResizeCursor(); | |
| 914 case CURSOR_EW_RESIZE: | |
| 915 return eastWestResizeCursor(); | |
| 916 case CURSOR_NESW_RESIZE: | |
| 917 return northEastSouthWestResizeCursor(); | |
| 918 case CURSOR_NWSE_RESIZE: | |
| 919 return northWestSouthEastResizeCursor(); | |
| 920 case CURSOR_COL_RESIZE: | |
| 921 return columnResizeCursor(); | |
| 922 case CURSOR_ROW_RESIZE: | |
| 923 return rowResizeCursor(); | |
| 924 case CURSOR_TEXT: | |
| 925 return iBeamCursor(); | |
| 926 case CURSOR_WAIT: | |
| 927 return waitCursor(); | |
| 928 case CURSOR_HELP: | |
| 929 return helpCursor(); | |
| 930 case CURSOR_VERTICAL_TEXT: | |
| 931 return verticalTextCursor(); | |
| 932 case CURSOR_CELL: | |
| 933 return cellCursor(); | |
| 934 case CURSOR_CONTEXT_MENU: | |
| 935 return contextMenuCursor(); | |
| 936 case CURSOR_PROGRESS: | |
| 937 return progressCursor(); | |
| 938 case CURSOR_NO_DROP: | |
| 939 return noDropCursor(); | |
| 940 case CURSOR_ALIAS: | |
| 941 return aliasCursor(); | |
| 942 case CURSOR_COPY: | |
| 943 return copyCursor(); | |
| 944 case CURSOR_NONE: | |
| 945 return noneCursor(); | |
| 946 case CURSOR_NOT_ALLOWED: | |
| 947 return notAllowedCursor(); | |
| 948 case CURSOR_DEFAULT: | |
| 949 return pointerCursor(); | |
| 950 case CURSOR_WEBKIT_ZOOM_IN: | |
| 951 return zoomInCursor(); | |
| 952 case CURSOR_WEBKIT_ZOOM_OUT: | |
| 953 return zoomOutCursor(); | |
| 954 } | |
| 955 return pointerCursor(); | |
| 956 } | |
| 957 | |
| 958 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) | |
| 959 { | |
| 960 if (!m_frame->document()) | |
| 961 return false; | |
| 962 | |
| 963 RefPtr<FrameView> protector(m_frame->view()); | |
| 964 | |
| 965 m_mousePressed = true; | |
| 966 m_currentMousePosition = mouseEvent.pos(); | |
| 967 m_mouseDownTimestamp = mouseEvent.timestamp(); | |
| 968 m_mouseDownMayStartDrag = false; | |
| 969 m_mouseDownMayStartSelect = false; | |
| 970 m_mouseDownMayStartAutoscroll = false; | |
| 971 m_mouseDownPos = m_frame->view()->windowToContents(mouseEvent.pos()); | |
| 972 m_mouseDownWasInSubframe = false; | |
| 973 | |
| 974 MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(false, t
rue), mouseEvent); | |
| 975 | |
| 976 if (!mev.targetNode()) { | |
| 977 invalidateClick(); | |
| 978 return false; | |
| 979 } | |
| 980 | |
| 981 m_mousePressNode = mev.targetNode(); | |
| 982 | |
| 983 Frame* subframe = subframeForTargetNode(mev.targetNode()); | |
| 984 if (subframe && passMousePressEventToSubframe(mev, subframe)) { | |
| 985 // Start capturing future events for this frame. We only do this if we
didn't clear | |
| 986 // the m_mousePressed flag, which may happen if an AppKit widget entered
a modal event loop. | |
| 987 if (m_mousePressed) | |
| 988 m_capturingMouseEventsNode = mev.targetNode(); | |
| 989 invalidateClick(); | |
| 990 return true; | |
| 991 } | |
| 992 | |
| 993 #if PLATFORM(WIN) | |
| 994 if (m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress() || m
_autoscrollInProgress) { | |
| 995 stopAutoscrollTimer(); | |
| 996 invalidateClick(); | |
| 997 return true; | |
| 998 } | |
| 999 | |
| 1000 if (mouseEvent.button() == MiddleButton && !mev.isOverLink()) { | |
| 1001 RenderObject* renderer = mev.targetNode()->renderer(); | |
| 1002 | |
| 1003 while (renderer && !renderer->canBeProgramaticallyScrolled(false)) { | |
| 1004 if (!renderer->parent() && renderer->node() == renderer->document()
&& renderer->document()->ownerElement()) | |
| 1005 renderer = renderer->document()->ownerElement()->renderer(); | |
| 1006 else | |
| 1007 renderer = renderer->parent(); | |
| 1008 } | |
| 1009 | |
| 1010 if (renderer) { | |
| 1011 m_panScrollInProgress = true; | |
| 1012 handleAutoscroll(renderer); | |
| 1013 invalidateClick(); | |
| 1014 return true; | |
| 1015 } | |
| 1016 } | |
| 1017 #endif | |
| 1018 | |
| 1019 m_clickCount = mouseEvent.clickCount(); | |
| 1020 m_clickNode = mev.targetNode(); | |
| 1021 | |
| 1022 RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->encl
osingLayer() : 0; | |
| 1023 IntPoint p = m_frame->view()->windowToContents(mouseEvent.pos()); | |
| 1024 if (layer && layer->isPointInResizeControl(p)) { | |
| 1025 layer->setInResizeMode(true); | |
| 1026 m_resizeLayer = layer; | |
| 1027 m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p); | |
| 1028 invalidateClick(); | |
| 1029 return true; | |
| 1030 } | |
| 1031 | |
| 1032 bool swallowEvent = dispatchMouseEvent(mousedownEvent, mev.targetNode(), tru
e, m_clickCount, mouseEvent, true); | |
| 1033 | |
| 1034 // If the hit testing originally determined the event was in a scrollbar, re
fetch the MouseEventWithHitTestResults | |
| 1035 // in case the scrollbar widget was destroyed when the mouse event was handl
ed. | |
| 1036 if (mev.scrollbar()) { | |
| 1037 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMou
se.get(); | |
| 1038 mev = prepareMouseEvent(HitTestRequest(true, true), mouseEvent); | |
| 1039 | |
| 1040 if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get
()) | |
| 1041 m_lastScrollbarUnderMouse = 0; | |
| 1042 } | |
| 1043 | |
| 1044 if (swallowEvent) { | |
| 1045 // scrollbars should get events anyway, even disabled controls might be
scrollable | |
| 1046 PlatformScrollbar* scrollbar = mev.scrollbar(); | |
| 1047 if (!scrollbar) | |
| 1048 scrollbar = m_frame->view()->scrollbarUnderMouse(mouseEvent); | |
| 1049 if (scrollbar) | |
| 1050 passMousePressEventToScrollbar(mev, scrollbar); | |
| 1051 } else { | |
| 1052 // Refetch the event target node if it currently is the shadow node insi
de an <input> element. | |
| 1053 // If a mouse event handler changes the input element type to one that h
as a widget associated, | |
| 1054 // we'd like to EventHandler::handleMousePressEvent to pass the event to
the widget and thus the | |
| 1055 // event target node can't still be the shadow node. | |
| 1056 if (mev.targetNode()->isShadowNode() && mev.targetNode()->shadowParentNo
de()->hasTagName(inputTag)) | |
| 1057 mev = prepareMouseEvent(HitTestRequest(true, true), mouseEvent); | |
| 1058 | |
| 1059 PlatformScrollbar* scrollbar = m_frame->view()->scrollbarUnderMouse(mous
eEvent); | |
| 1060 if (!scrollbar) | |
| 1061 scrollbar = mev.scrollbar(); | |
| 1062 if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar)) | |
| 1063 swallowEvent = true; | |
| 1064 else | |
| 1065 swallowEvent = handleMousePressEvent(mev); | |
| 1066 } | |
| 1067 | |
| 1068 return swallowEvent; | |
| 1069 } | |
| 1070 | |
| 1071 // This method only exists for platforms that don't know how to deliver | |
| 1072 bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEv
ent) | |
| 1073 { | |
| 1074 if (!m_frame->document()) | |
| 1075 return false; | |
| 1076 | |
| 1077 RefPtr<FrameView> protector(m_frame->view()); | |
| 1078 | |
| 1079 // We get this instead of a second mouse-up | |
| 1080 m_mousePressed = false; | |
| 1081 m_currentMousePosition = mouseEvent.pos(); | |
| 1082 | |
| 1083 MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(false, t
rue), mouseEvent); | |
| 1084 Frame* subframe = subframeForTargetNode(mev.targetNode()); | |
| 1085 if (subframe && passMousePressEventToSubframe(mev, subframe)) { | |
| 1086 m_capturingMouseEventsNode = 0; | |
| 1087 return true; | |
| 1088 } | |
| 1089 | |
| 1090 m_clickCount = mouseEvent.clickCount(); | |
| 1091 bool swallowMouseUpEvent = dispatchMouseEvent(mouseupEvent, mev.targetNode()
, true, m_clickCount, mouseEvent, false); | |
| 1092 | |
| 1093 bool swallowClickEvent = false; | |
| 1094 // Don't ever dispatch click events for right clicks | |
| 1095 if (mouseEvent.button() != RightButton && mev.targetNode() == m_clickNode) | |
| 1096 swallowClickEvent = dispatchMouseEvent(clickEvent, mev.targetNode(), tru
e, m_clickCount, mouseEvent, true); | |
| 1097 | |
| 1098 bool swallowMouseReleaseEvent = false; | |
| 1099 if (!swallowMouseUpEvent) | |
| 1100 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev); | |
| 1101 | |
| 1102 invalidateClick(); | |
| 1103 | |
| 1104 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent; | |
| 1105 } | |
| 1106 | |
| 1107 bool EventHandler::mouseMoved(const PlatformMouseEvent& event) | |
| 1108 { | |
| 1109 HitTestResult hoveredNode = HitTestResult(IntPoint()); | |
| 1110 bool result = handleMouseMoveEvent(event, &hoveredNode); | |
| 1111 | |
| 1112 Page* page = m_frame->page(); | |
| 1113 if (!page) | |
| 1114 return result; | |
| 1115 | |
| 1116 hoveredNode.setToNonShadowAncestor(); | |
| 1117 page->chrome()->mouseDidMoveOverElement(hoveredNode, event.modifierFlags()); | |
| 1118 page->chrome()->setToolTip(hoveredNode); | |
| 1119 return result; | |
| 1120 } | |
| 1121 | |
| 1122 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi
tTestResult* hoveredNode) | |
| 1123 { | |
| 1124 // in Radar 3703768 we saw frequent crashes apparently due to the | |
| 1125 // part being null here, which seems impossible, so check for nil | |
| 1126 // but also assert so that we can try to figure this out in debug | |
| 1127 // builds, if it happens. | |
| 1128 ASSERT(m_frame); | |
| 1129 if (!m_frame || !m_frame->document()) | |
| 1130 return false; | |
| 1131 | |
| 1132 RefPtr<FrameView> protector(m_frame->view()); | |
| 1133 m_currentMousePosition = mouseEvent.pos(); | |
| 1134 | |
| 1135 if (m_hoverTimer.isActive()) | |
| 1136 m_hoverTimer.stop(); | |
| 1137 | |
| 1138 #if ENABLE(SVG) | |
| 1139 if (m_svgPan) { | |
| 1140 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMouse
Position); | |
| 1141 return true; | |
| 1142 } | |
| 1143 #endif | |
| 1144 | |
| 1145 if (m_frameSetBeingResized) | |
| 1146 return dispatchMouseEvent(mousemoveEvent, m_frameSetBeingResized.get(),
false, 0, mouseEvent, false); | |
| 1147 | |
| 1148 // Send events right to a scrollbar if the mouse is pressed. | |
| 1149 if (m_lastScrollbarUnderMouse && m_mousePressed) | |
| 1150 return m_lastScrollbarUnderMouse->handleMouseMoveEvent(mouseEvent); | |
| 1151 | |
| 1152 // Treat mouse move events while the mouse is pressed as "read-only" in prep
areMouseEvent | |
| 1153 // if we are allowed to select. | |
| 1154 // This means that :hover and :active freeze in the state they were in when
the mouse | |
| 1155 // was pressed, rather than updating for nodes the mouse moves over as you h
old the mouse down. | |
| 1156 HitTestRequest request(m_mousePressed && m_mouseDownMayStartSelect, m_mouseP
ressed, true); | |
| 1157 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent); | |
| 1158 if (hoveredNode) | |
| 1159 *hoveredNode = mev.hitTestResult(); | |
| 1160 | |
| 1161 PlatformScrollbar* scrollbar = 0; | |
| 1162 | |
| 1163 if (m_resizeLayer && m_resizeLayer->inResizeMode()) | |
| 1164 m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner); | |
| 1165 else { | |
| 1166 if (m_frame->view()) | |
| 1167 scrollbar = m_frame->view()->scrollbarUnderMouse(mouseEvent); | |
| 1168 | |
| 1169 if (!scrollbar) | |
| 1170 scrollbar = mev.scrollbar(); | |
| 1171 | |
| 1172 if (m_lastScrollbarUnderMouse != scrollbar) { | |
| 1173 // Send mouse exited to the old scrollbar. | |
| 1174 if (m_lastScrollbarUnderMouse) | |
| 1175 m_lastScrollbarUnderMouse->handleMouseOutEvent(mouseEvent); | |
| 1176 m_lastScrollbarUnderMouse = m_mousePressed ? 0 : scrollbar; | |
| 1177 } | |
| 1178 } | |
| 1179 | |
| 1180 bool swallowEvent = false; | |
| 1181 Node* targetNode = m_capturingMouseEventsNode ? m_capturingMouseEventsNode.g
et() : mev.targetNode(); | |
| 1182 RefPtr<Frame> newSubframe = subframeForTargetNode(targetNode); | |
| 1183 | |
| 1184 // We want mouseouts to happen first, from the inside out. First send a mov
e event to the last subframe so that it will fire mouseouts. | |
| 1185 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree()->is
DescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe) | |
| 1186 passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get()); | |
| 1187 | |
| 1188 if (newSubframe) { | |
| 1189 // Update over/out state before passing the event to the subframe. | |
| 1190 updateMouseEventTargetNode(mev.targetNode(), mouseEvent, true); | |
| 1191 | |
| 1192 // Event dispatch in updateMouseEventTargetNode may have caused the subf
rame of the target | |
| 1193 // node to be detached from its FrameView, in which case the event shoul
d not be passed. | |
| 1194 | |
| 1195 // Manually merge changes from webkit trunk to fix the crash for | |
| 1196 // http://www.coolpc.com.tw/evaluate.php | |
| 1197 // See http://trac.webkit.org/changeset/31788. | |
| 1198 if (newSubframe->view()) | |
| 1199 swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(),
hoveredNode); | |
| 1200 } else { | |
| 1201 if (scrollbar && !m_mousePressed) | |
| 1202 scrollbar->handleMouseMoveEvent(mouseEvent); // Handle hover effects
on platforms that support visual feedback on scrollbar hovering. | |
| 1203 if ((!m_resizeLayer || !m_resizeLayer->inResizeMode()) && !m_frame->page
()->mainFrame()->eventHandler()->panScrollInProgress() && m_frame->view()) | |
| 1204 m_frame->view()->setCursor(selectCursor(mev, scrollbar)); | |
| 1205 } | |
| 1206 | |
| 1207 m_lastMouseMoveEventSubframe = newSubframe; | |
| 1208 | |
| 1209 if (swallowEvent) | |
| 1210 return true; | |
| 1211 | |
| 1212 swallowEvent = dispatchMouseEvent(mousemoveEvent, mev.targetNode(), false, 0
, mouseEvent, true); | |
| 1213 if (!swallowEvent) | |
| 1214 swallowEvent = handleMouseDraggedEvent(mev); | |
| 1215 | |
| 1216 return swallowEvent; | |
| 1217 } | |
| 1218 | |
| 1219 void EventHandler::invalidateClick() | |
| 1220 { | |
| 1221 m_clickCount = 0; | |
| 1222 m_clickNode = 0; | |
| 1223 } | |
| 1224 | |
| 1225 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent) | |
| 1226 { | |
| 1227 if (!m_frame->document()) | |
| 1228 return false; | |
| 1229 | |
| 1230 RefPtr<FrameView> protector(m_frame->view()); | |
| 1231 | |
| 1232 m_mousePressed = false; | |
| 1233 m_currentMousePosition = mouseEvent.pos(); | |
| 1234 | |
| 1235 #if ENABLE(SVG) | |
| 1236 if (m_svgPan) { | |
| 1237 m_svgPan = false; | |
| 1238 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMouse
Position); | |
| 1239 return true; | |
| 1240 } | |
| 1241 #endif | |
| 1242 | |
| 1243 if (m_frameSetBeingResized) | |
| 1244 return dispatchMouseEvent(mouseupEvent, m_frameSetBeingResized.get(), tr
ue, m_clickCount, mouseEvent, false); | |
| 1245 | |
| 1246 if (m_lastScrollbarUnderMouse) { | |
| 1247 invalidateClick(); | |
| 1248 return m_lastScrollbarUnderMouse->handleMouseReleaseEvent(mouseEvent); | |
| 1249 } | |
| 1250 | |
| 1251 MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(false, f
alse, false, true), mouseEvent); | |
| 1252 Node* targetNode = m_capturingMouseEventsNode.get() ? m_capturingMouseEvents
Node.get() : mev.targetNode(); | |
| 1253 Frame* subframe = subframeForTargetNode(targetNode); | |
| 1254 if (subframe && passMouseReleaseEventToSubframe(mev, subframe)) { | |
| 1255 m_capturingMouseEventsNode = 0; | |
| 1256 return true; | |
| 1257 } | |
| 1258 | |
| 1259 bool swallowMouseUpEvent = dispatchMouseEvent(mouseupEvent, mev.targetNode()
, true, m_clickCount, mouseEvent, false); | |
| 1260 | |
| 1261 // Don't ever dispatch click events for right clicks | |
| 1262 bool swallowClickEvent = false; | |
| 1263 if (m_clickCount > 0 && mouseEvent.button() != RightButton && mev.targetNode
() == m_clickNode) | |
| 1264 swallowClickEvent = dispatchMouseEvent(clickEvent, mev.targetNode(), tru
e, m_clickCount, mouseEvent, true); | |
| 1265 | |
| 1266 if (m_resizeLayer) { | |
| 1267 m_resizeLayer->setInResizeMode(false); | |
| 1268 m_resizeLayer = 0; | |
| 1269 } | |
| 1270 | |
| 1271 bool swallowMouseReleaseEvent = false; | |
| 1272 if (!swallowMouseUpEvent) | |
| 1273 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev); | |
| 1274 | |
| 1275 invalidateClick(); | |
| 1276 | |
| 1277 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent; | |
| 1278 } | |
| 1279 | |
| 1280 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTa
rget, const PlatformMouseEvent& event, Clipboard* clipboard) | |
| 1281 { | |
| 1282 IntPoint contentsPos = m_frame->view()->windowToContents(event.pos()); | |
| 1283 | |
| 1284 RefPtr<MouseEvent> me = MouseEvent::create(eventType, | |
| 1285 true, true, m_frame->document()->defaultView(), | |
| 1286 0, event.globalX(), event.globalY(), contentsPos.x(), contentsPos.y(), | |
| 1287 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), | |
| 1288 0, 0, clipboard); | |
| 1289 | |
| 1290 ExceptionCode ec = 0; | |
| 1291 EventTargetNodeCast(dragTarget)->dispatchEvent(me.get(), ec, true); | |
| 1292 return me->defaultPrevented(); | |
| 1293 } | |
| 1294 | |
| 1295 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard*
clipboard) | |
| 1296 { | |
| 1297 bool accept = false; | |
| 1298 | |
| 1299 if (!m_frame->document()) | |
| 1300 return false; | |
| 1301 | |
| 1302 if (!m_frame->view()) | |
| 1303 return false; | |
| 1304 | |
| 1305 MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(true, fa
lse), event); | |
| 1306 | |
| 1307 // Drag events should never go to text nodes (following IE, and proper mouse
over/out dispatch) | |
| 1308 Node* newTarget = mev.targetNode(); | |
| 1309 if (newTarget && newTarget->isTextNode()) | |
| 1310 newTarget = newTarget->parentNode(); | |
| 1311 if (newTarget) | |
| 1312 newTarget = newTarget->shadowAncestorNode(); | |
| 1313 | |
| 1314 if (m_dragTarget != newTarget) { | |
| 1315 // FIXME: this ordering was explicitly chosen to match WinIE. However, | |
| 1316 // it is sometimes incorrect when dragging within subframes, as seen wit
h | |
| 1317 // LayoutTests/fast/events/drag-in-frames.html. | |
| 1318 if (newTarget) | |
| 1319 if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeT
ag)) | |
| 1320 accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentF
rame()->eventHandler()->updateDragAndDrop(event, clipboard); | |
| 1321 else | |
| 1322 accept = dispatchDragEvent(dragenterEvent, newTarget, event, cli
pboard); | |
| 1323 | |
| 1324 if (m_dragTarget) { | |
| 1325 Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->
hasTagName(iframeTag)) | |
| 1326 ? static_cast<HTMLFrameElementBase*>(m_dragTarget.ge
t())->contentFrame() : 0; | |
| 1327 if (frame) | |
| 1328 accept = frame->eventHandler()->updateDragAndDrop(event, clipboa
rd); | |
| 1329 else | |
| 1330 dispatchDragEvent(dragleaveEvent, m_dragTarget.get(), event, cli
pboard); | |
| 1331 } | |
| 1332 } else { | |
| 1333 if (newTarget) | |
| 1334 if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeT
ag)) | |
| 1335 accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentF
rame()->eventHandler()->updateDragAndDrop(event, clipboard); | |
| 1336 else | |
| 1337 accept = dispatchDragEvent(dragoverEvent, newTarget, event, clip
board); | |
| 1338 } | |
| 1339 m_dragTarget = newTarget; | |
| 1340 | |
| 1341 return accept; | |
| 1342 } | |
| 1343 | |
| 1344 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard*
clipboard) | |
| 1345 { | |
| 1346 if (m_dragTarget) { | |
| 1347 Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasT
agName(iframeTag)) | |
| 1348 ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())
->contentFrame() : 0; | |
| 1349 if (frame) | |
| 1350 frame->eventHandler()->cancelDragAndDrop(event, clipboard); | |
| 1351 else | |
| 1352 dispatchDragEvent(dragleaveEvent, m_dragTarget.get(), event, clipboa
rd); | |
| 1353 } | |
| 1354 clearDragState(); | |
| 1355 } | |
| 1356 | |
| 1357 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard
* clipboard) | |
| 1358 { | |
| 1359 bool accept = false; | |
| 1360 if (m_dragTarget) { | |
| 1361 Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasT
agName(iframeTag)) | |
| 1362 ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())
->contentFrame() : 0; | |
| 1363 if (frame) | |
| 1364 accept = frame->eventHandler()->performDragAndDrop(event, clipboard)
; | |
| 1365 else | |
| 1366 accept = dispatchDragEvent(dropEvent, m_dragTarget.get(), event, cli
pboard); | |
| 1367 } | |
| 1368 clearDragState(); | |
| 1369 return accept; | |
| 1370 } | |
| 1371 | |
| 1372 void EventHandler::clearDragState() | |
| 1373 { | |
| 1374 m_dragTarget = 0; | |
| 1375 m_capturingMouseEventsNode = 0; | |
| 1376 #if PLATFORM(MAC) | |
| 1377 m_sendingEventToSubview = false; | |
| 1378 #endif | |
| 1379 } | |
| 1380 | |
| 1381 Node* EventHandler::nodeUnderMouse() const | |
| 1382 { | |
| 1383 return m_nodeUnderMouse.get(); | |
| 1384 } | |
| 1385 | |
| 1386 void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n) | |
| 1387 { | |
| 1388 m_capturingMouseEventsNode = n; | |
| 1389 } | |
| 1390 | |
| 1391 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestReques
t& request, const PlatformMouseEvent& mev) | |
| 1392 { | |
| 1393 ASSERT(m_frame); | |
| 1394 ASSERT(m_frame->document()); | |
| 1395 | |
| 1396 IntPoint documentPoint = m_frame->view()->windowToContents(mev.pos()); | |
| 1397 return m_frame->document()->prepareMouseEvent(request, documentPoint, mev); | |
| 1398 } | |
| 1399 | |
| 1400 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMo
useEvent& mouseEvent, bool fireMouseOverOut) | |
| 1401 { | |
| 1402 Node* result = targetNode; | |
| 1403 | |
| 1404 // If we're capturing, we always go right to that node. | |
| 1405 if (m_capturingMouseEventsNode) | |
| 1406 result = m_capturingMouseEventsNode.get(); | |
| 1407 else { | |
| 1408 // If the target node is a text node, dispatch on the parent node - rdar
://4196646 | |
| 1409 if (result && result->isTextNode()) | |
| 1410 result = result->parentNode(); | |
| 1411 if (result) | |
| 1412 result = result->shadowAncestorNode(); | |
| 1413 } | |
| 1414 m_nodeUnderMouse = result; | |
| 1415 | |
| 1416 // Fire mouseout/mouseover if the mouse has shifted to a different node. | |
| 1417 if (fireMouseOverOut) { | |
| 1418 if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame-
>document()) { | |
| 1419 m_lastNodeUnderMouse = 0; | |
| 1420 m_lastScrollbarUnderMouse = 0; | |
| 1421 } | |
| 1422 | |
| 1423 if (m_lastNodeUnderMouse != m_nodeUnderMouse) { | |
| 1424 // send mouseout event to the old node | |
| 1425 if (m_lastNodeUnderMouse) | |
| 1426 EventTargetNodeCast(m_lastNodeUnderMouse.get())->dispatchMouseEv
ent(mouseEvent, mouseoutEvent, 0, m_nodeUnderMouse.get()); | |
| 1427 // send mouseover event to the new node | |
| 1428 if (m_nodeUnderMouse) | |
| 1429 EventTargetNodeCast(m_nodeUnderMouse.get())->dispatchMouseEvent(
mouseEvent, mouseoverEvent, 0, m_lastNodeUnderMouse.get()); | |
| 1430 } | |
| 1431 m_lastNodeUnderMouse = m_nodeUnderMouse; | |
| 1432 } | |
| 1433 } | |
| 1434 | |
| 1435 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targe
tNode, bool cancelable, int clickCount, const PlatformMouseEvent& mouseEvent, bo
ol setUnder) | |
| 1436 { | |
| 1437 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder); | |
| 1438 | |
| 1439 bool swallowEvent = false; | |
| 1440 | |
| 1441 if (m_nodeUnderMouse) | |
| 1442 swallowEvent = EventTargetNodeCast(m_nodeUnderMouse.get())->dispatchMous
eEvent(mouseEvent, eventType, clickCount); | |
| 1443 | |
| 1444 if (!swallowEvent && eventType == mousedownEvent) { | |
| 1445 // Blur current focus node when a link/button is clicked; this | |
| 1446 // is expected by some sites that rely on onChange handlers running | |
| 1447 // from form fields before the button click is processed. | |
| 1448 Node* node = m_nodeUnderMouse.get(); | |
| 1449 RenderObject* renderer = node ? node->renderer() : 0; | |
| 1450 | |
| 1451 // Walk up the render tree to search for a node to focus. | |
| 1452 // Walking up the DOM tree wouldn't work for shadow trees, like those be
hind the engine-based text fields. | |
| 1453 while (renderer) { | |
| 1454 node = renderer->element(); | |
| 1455 if (node && node->isFocusable()) { | |
| 1456 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we
don't focus a | |
| 1457 // node on mouse down if it's selected and inside a focused node
. It will be | |
| 1458 // focused if the user does a mouseup over it, however, because
the mouseup | |
| 1459 // will set a selection inside it, which will call setFocuseNode
IfNeeded. | |
| 1460 ExceptionCode ec = 0; | |
| 1461 Node* n = node->isShadowNode() ? node->shadowParentNode() : node
; | |
| 1462 if (m_frame->selection()->isRange() && | |
| 1463 m_frame->selection()->toRange()->compareNode(n, ec) == Range
::NODE_INSIDE && | |
| 1464 n->isDescendantOf(m_frame->document()->focusedNode())) | |
| 1465 return false; | |
| 1466 | |
| 1467 break; | |
| 1468 } | |
| 1469 | |
| 1470 renderer = renderer->parent(); | |
| 1471 } | |
| 1472 // If focus shift is blocked, we eat the event. Note we should never cl
ear swallowEvent | |
| 1473 // if the page already set it (e.g., by canceling default behavior). | |
| 1474 if (node && node->isMouseFocusable()) { | |
| 1475 if (!m_frame->page()->focusController()->setFocusedNode(node, m_fram
e)) | |
| 1476 swallowEvent = true; | |
| 1477 } else if (!node || !node->focused()) { | |
| 1478 if (!m_frame->page()->focusController()->setFocusedNode(0, m_frame)) | |
| 1479 swallowEvent = true; | |
| 1480 } | |
| 1481 } | |
| 1482 | |
| 1483 return swallowEvent; | |
| 1484 } | |
| 1485 | |
| 1486 bool EventHandler::handleWheelEvent(PlatformWheelEvent& e) | |
| 1487 { | |
| 1488 Document* doc = m_frame->document(); | |
| 1489 if (!doc) | |
| 1490 return false; | |
| 1491 | |
| 1492 RenderObject* docRenderer = doc->renderer(); | |
| 1493 if (!docRenderer) | |
| 1494 return false; | |
| 1495 | |
| 1496 IntPoint vPoint = m_frame->view()->windowToContents(e.pos()); | |
| 1497 | |
| 1498 HitTestRequest request(true, false); | |
| 1499 HitTestResult result(vPoint); | |
| 1500 doc->renderer()->layer()->hitTest(request, result); | |
| 1501 Node* node = result.innerNode(); | |
| 1502 | |
| 1503 if (node) { | |
| 1504 // Figure out which view to send the event to. | |
| 1505 RenderObject* target = node->renderer(); | |
| 1506 | |
| 1507 if (target && target->isWidget()) { | |
| 1508 Widget* widget = static_cast<RenderWidget*>(target)->widget(); | |
| 1509 | |
| 1510 if (widget && passWheelEventToWidget(e, widget)) { | |
| 1511 e.accept(); | |
| 1512 return true; | |
| 1513 } | |
| 1514 } | |
| 1515 | |
| 1516 node = node->shadowAncestorNode(); | |
| 1517 EventTargetNodeCast(node)->dispatchWheelEvent(e); | |
| 1518 if (e.isAccepted()) | |
| 1519 return true; | |
| 1520 | |
| 1521 if (node->renderer()) { | |
| 1522 // Just break up into two scrolls if we need to. Diagonal movement
on | |
| 1523 // a MacBook pro is an example of a 2-dimensional mouse wheel event
(where both deltaX and deltaY can be set). | |
| 1524 float deltaX = e.isContinuous() ? e.continuousDeltaX() : e.deltaX(); | |
| 1525 float deltaY = e.isContinuous() ? e.continuousDeltaY() : e.deltaY(); | |
| 1526 | |
| 1527 scrollAndAcceptEvent(deltaX, ScrollLeft, ScrollRight, e.isPageXScrol
lModeEnabled(), e, node, m_frame->page()->chrome()->windowRect().width()); | |
| 1528 scrollAndAcceptEvent(deltaY, ScrollUp, ScrollDown, e.isPageYScrollMo
deEnabled(), e, node, m_frame->page()->chrome()->windowRect().height()); | |
| 1529 } | |
| 1530 } | |
| 1531 | |
| 1532 if (!e.isAccepted()) | |
| 1533 m_frame->view()->wheelEvent(e); | |
| 1534 | |
| 1535 return e.isAccepted(); | |
| 1536 } | |
| 1537 | |
| 1538 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event) | |
| 1539 { | |
| 1540 Document* doc = m_frame->document(); | |
| 1541 FrameView* v = m_frame->view(); | |
| 1542 if (!doc || !v) | |
| 1543 return false; | |
| 1544 | |
| 1545 bool swallowEvent; | |
| 1546 IntPoint viewportPos = v->windowToContents(event.pos()); | |
| 1547 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(HitTestRequest(fal
se, true), viewportPos, event); | |
| 1548 | |
| 1549 #if 0 | |
| 1550 // The following commented out code tries to select the word below the | |
| 1551 // mouse cursor on right click. This used to be behavior that could be | |
| 1552 // changed by webkit embedders, but in change 24499, that functionality was | |
| 1553 // removed. | |
| 1554 // https://bugs.webkit.org/show_bug.cgi?id=15279 | |
| 1555 | |
| 1556 if (!m_frame->selection()->contains(viewportPos) && | |
| 1557 // FIXME: In the editable case, word selection sometimes selects content
that isn't underneath the mouse. | |
| 1558 // If the selection is non-editable, we do word selection to make it eas
ier to use the contextual menu items | |
| 1559 // available for text selections. But only if we're above text. | |
| 1560 (m_frame->selection()->isContentEditable() || mev.targetNode() && mev.ta
rgetNode()->isTextNode())) { | |
| 1561 m_mouseDownMayStartSelect = true; // context menu events are always allo
wed to perform a selection | |
| 1562 selectClosestWordOrLinkFromMouseEvent(mev); | |
| 1563 } | |
| 1564 #endif | |
| 1565 swallowEvent = dispatchMouseEvent(contextmenuEvent, mev.targetNode(), true,
0, event, true); | |
| 1566 | |
| 1567 return swallowEvent; | |
| 1568 } | |
| 1569 | |
| 1570 void EventHandler::scheduleHoverStateUpdate() | |
| 1571 { | |
| 1572 if (!m_hoverTimer.isActive()) | |
| 1573 m_hoverTimer.startOneShot(0); | |
| 1574 } | |
| 1575 | |
| 1576 // Whether or not a mouse down can begin the creation of a selection. Fires the
selectStart event. | |
| 1577 bool EventHandler::canMouseDownStartSelect(Node* node) | |
| 1578 { | |
| 1579 if (!node || !node->renderer()) | |
| 1580 return true; | |
| 1581 | |
| 1582 // Some controls and images can't start a select on a mouse down. | |
| 1583 if (!node->canStartSelection()) | |
| 1584 return false; | |
| 1585 | |
| 1586 for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) | |
| 1587 if (Node* node = curr->element()) | |
| 1588 return EventTargetNodeCast(node)->dispatchHTMLEvent(selectstartEvent
, true, true); | |
| 1589 | |
| 1590 return true; | |
| 1591 } | |
| 1592 | |
| 1593 bool EventHandler::canMouseDragExtendSelect(Node* node) | |
| 1594 { | |
| 1595 if (!node || !node->renderer()) | |
| 1596 return true; | |
| 1597 | |
| 1598 for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) | |
| 1599 if (Node* node = curr->element()) | |
| 1600 return EventTargetNodeCast(node)->dispatchHTMLEvent(selectstartEvent
, true, true); | |
| 1601 | |
| 1602 return true; | |
| 1603 } | |
| 1604 | |
| 1605 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet) | |
| 1606 { | |
| 1607 m_frameSetBeingResized = frameSet; | |
| 1608 } | |
| 1609 | |
| 1610 void EventHandler::resizeLayerDestroyed() | |
| 1611 { | |
| 1612 ASSERT(m_resizeLayer); | |
| 1613 m_resizeLayer = 0; | |
| 1614 } | |
| 1615 | |
| 1616 void EventHandler::hoverTimerFired(Timer<EventHandler>*) | |
| 1617 { | |
| 1618 m_hoverTimer.stop(); | |
| 1619 | |
| 1620 ASSERT(m_frame); | |
| 1621 ASSERT(m_frame->document()); | |
| 1622 | |
| 1623 if (RenderObject* renderer = m_frame->contentRenderer()) { | |
| 1624 HitTestResult result(m_frame->view()->windowToContents(m_currentMousePos
ition)); | |
| 1625 renderer->layer()->hitTest(HitTestRequest(false, false, true), result); | |
| 1626 m_frame->document()->updateRendering(); | |
| 1627 } | |
| 1628 } | |
| 1629 | |
| 1630 static EventTargetNode* eventTargetNodeForDocument(Document* doc) | |
| 1631 { | |
| 1632 if (!doc) | |
| 1633 return 0; | |
| 1634 Node* node = doc->focusedNode(); | |
| 1635 if (!node) { | |
| 1636 if (doc->isHTMLDocument()) | |
| 1637 node = doc->body(); | |
| 1638 else | |
| 1639 node = doc->documentElement(); | |
| 1640 if (!node) | |
| 1641 return 0; | |
| 1642 } | |
| 1643 return EventTargetNodeCast(node); | |
| 1644 } | |
| 1645 | |
| 1646 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt) | |
| 1647 { | |
| 1648 if ((evt.modifiers() & s_accessKeyModifiers) != s_accessKeyModifiers) | |
| 1649 return false; | |
| 1650 String key = evt.unmodifiedText(); | |
| 1651 Element* elem = m_frame->document()->getElementByAccessKey(key.lower()); | |
| 1652 if (!elem) | |
| 1653 return false; | |
| 1654 elem->accessKeyAction(false); | |
| 1655 return true; | |
| 1656 } | |
| 1657 | |
| 1658 #if !PLATFORM(MAC) | |
| 1659 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const | |
| 1660 { | |
| 1661 return false; | |
| 1662 } | |
| 1663 #endif | |
| 1664 | |
| 1665 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent) | |
| 1666 { | |
| 1667 #if PLATFORM(WIN) || (PLATFORM(WX) && PLATFORM(WIN_OS)) | |
| 1668 String escKeyId = "U+001B"; | |
| 1669 // If a key is pressed while the autoscroll/panScroll is in progress then we
want to stop | |
| 1670 if (initialKeyEvent.keyIdentifier() == escKeyId && m_frame->page()->mainFram
e()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress) | |
| 1671 stopAutoscrollTimer(); | |
| 1672 #endif | |
| 1673 | |
| 1674 // Check for cases where we are too early for events -- possible unmatched k
ey up | |
| 1675 // from pressing return in the location bar. | |
| 1676 RefPtr<EventTargetNode> node = eventTargetNodeForDocument(m_frame->document(
)); | |
| 1677 if (!node) | |
| 1678 return false; | |
| 1679 | |
| 1680 // FIXME: what is this doing here, in keyboard event handler? | |
| 1681 m_frame->loader()->resetMultipleFormSubmissionProtection(); | |
| 1682 | |
| 1683 // In IE, access keys are special, they are handled after default keydown pr
ocessing, but cannot be canceled - this is hard to match. | |
| 1684 // On Mac OS X, we process them before dispatching keydown, as the default k
eydown handler implements Emacs key bindings, which may conflict | |
| 1685 // with access keys. Then we dispatch keydown, but suppress its default hand
ling. | |
| 1686 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatch
ing a keypress event for WM_SYSCHAR messages. | |
| 1687 // Other platforms currently match either Mac or Windows behavior, depending
on whether they send combined KeyDown events. | |
| 1688 bool matchedAnAccessKey = false; | |
| 1689 if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyDown) | |
| 1690 matchedAnAccessKey = handleAccessKey(initialKeyEvent); | |
| 1691 | |
| 1692 // FIXME: it would be fair to let an input method handle KeyUp events before
DOM dispatch. | |
| 1693 if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyUp || initialKeyEven
t.type() == PlatformKeyboardEvent::Char) | |
| 1694 return !node->dispatchKeyEvent(initialKeyEvent); | |
| 1695 | |
| 1696 bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks(); | |
| 1697 | |
| 1698 ExceptionCode ec; | |
| 1699 PlatformKeyboardEvent keyDownEvent = initialKeyEvent; | |
| 1700 if (keyDownEvent.type() != PlatformKeyboardEvent::RawKeyDown) | |
| 1701 keyDownEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown,
backwardCompatibilityMode); | |
| 1702 RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame-
>document()->defaultView()); | |
| 1703 if (matchedAnAccessKey) | |
| 1704 keydown->setDefaultPrevented(true); | |
| 1705 keydown->setTarget(node); | |
| 1706 | |
| 1707 if (initialKeyEvent.type() == PlatformKeyboardEvent::RawKeyDown) { | |
| 1708 node->dispatchEvent(keydown, ec, true); | |
| 1709 return keydown->defaultHandled() || keydown->defaultPrevented(); | |
| 1710 } | |
| 1711 | |
| 1712 // Run input method in advance of DOM event handling. This may result in th
e IM | |
| 1713 // modifying the page prior the keydown event, but this behaviour is necessa
ry | |
| 1714 // in order to match IE: | |
| 1715 // 1. preventing default handling of keydown and keypress events has no effe
ct on IM input; | |
| 1716 // 2. if an input method handles the event, its keyCode is set to 229 in key
down event. | |
| 1717 m_frame->editor()->handleInputMethodKeydown(keydown.get()); | |
| 1718 | |
| 1719 bool handledByInputMethod = keydown->defaultHandled(); | |
| 1720 | |
| 1721 if (handledByInputMethod) { | |
| 1722 keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode); | |
| 1723 keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defau
ltView()); | |
| 1724 keydown->setTarget(node); | |
| 1725 keydown->setDefaultHandled(); | |
| 1726 } | |
| 1727 | |
| 1728 node->dispatchEvent(keydown, ec, true); | |
| 1729 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented(
); | |
| 1730 if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode)) | |
| 1731 return keydownResult; | |
| 1732 | |
| 1733 // Focus may have changed during keydown handling, so refetch node. | |
| 1734 // But if we are dispatching a fake backward compatibility keypress, then we
pretend that the keypress happened on the original node. | |
| 1735 if (!keydownResult) { | |
| 1736 node = eventTargetNodeForDocument(m_frame->document()); | |
| 1737 if (!node) | |
| 1738 return false; | |
| 1739 } | |
| 1740 | |
| 1741 PlatformKeyboardEvent keyPressEvent = initialKeyEvent; | |
| 1742 keyPressEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::Char, backward
CompatibilityMode); | |
| 1743 if (keyPressEvent.text().isEmpty()) | |
| 1744 return keydownResult; | |
| 1745 RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_fram
e->document()->defaultView()); | |
| 1746 keypress->setTarget(node); | |
| 1747 if (keydownResult) | |
| 1748 keypress->setDefaultPrevented(true); | |
| 1749 #if PLATFORM(MAC) | |
| 1750 keypress->keypressCommands() = keydown->keypressCommands(); | |
| 1751 #endif | |
| 1752 node->dispatchEvent(keypress, ec, true); | |
| 1753 | |
| 1754 return keydownResult || keypress->defaultPrevented() || keypress->defaultHan
dled(); | |
| 1755 } | |
| 1756 | |
| 1757 void EventHandler::handleKeyboardSelectionMovement(KeyboardEvent* event) | |
| 1758 { | |
| 1759 if (!event) | |
| 1760 return; | |
| 1761 | |
| 1762 String key = event->keyIdentifier(); | |
| 1763 bool isShifted = event->getModifierState("Shift"); | |
| 1764 bool isOptioned = event->getModifierState("Alt"); | |
| 1765 | |
| 1766 if (key == "Up") { | |
| 1767 m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND :
SelectionController::MOVE, SelectionController::BACKWARD, LineGranularity, true
); | |
| 1768 event->setDefaultHandled(); | |
| 1769 } | |
| 1770 else if (key == "Down") { | |
| 1771 m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND :
SelectionController::MOVE, SelectionController::FORWARD, LineGranularity, true)
; | |
| 1772 event->setDefaultHandled(); | |
| 1773 } | |
| 1774 else if (key == "Left") { | |
| 1775 m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND :
SelectionController::MOVE, SelectionController::LEFT, (isOptioned) ? WordGranul
arity : CharacterGranularity, true); | |
| 1776 event->setDefaultHandled(); | |
| 1777 } | |
| 1778 else if (key == "Right") { | |
| 1779 m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND :
SelectionController::MOVE, SelectionController::RIGHT, (isOptioned) ? WordGranu
larity : CharacterGranularity, true); | |
| 1780 event->setDefaultHandled(); | |
| 1781 } | |
| 1782 } | |
| 1783 | |
| 1784 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event) | |
| 1785 { | |
| 1786 if (event->type() == keydownEvent) { | |
| 1787 m_frame->editor()->handleKeyboardEvent(event); | |
| 1788 if (event->defaultHandled()) | |
| 1789 return; | |
| 1790 if (event->keyIdentifier() == "U+0009") | |
| 1791 defaultTabEventHandler(event); | |
| 1792 | |
| 1793 // provides KB navigation and selection for enhanced accessibility users | |
| 1794 if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled()) | |
| 1795 handleKeyboardSelectionMovement(event); | |
| 1796 } | |
| 1797 if (event->type() == keypressEvent) { | |
| 1798 m_frame->editor()->handleKeyboardEvent(event); | |
| 1799 if (event->defaultHandled()) | |
| 1800 return; | |
| 1801 } | |
| 1802 } | |
| 1803 | |
| 1804 bool EventHandler::dragHysteresisExceeded(const FloatPoint& floatDragViewportLoc
ation) const | |
| 1805 { | |
| 1806 IntPoint dragViewportLocation((int)floatDragViewportLocation.x(), (int)float
DragViewportLocation.y()); | |
| 1807 return dragHysteresisExceeded(dragViewportLocation); | |
| 1808 } | |
| 1809 | |
| 1810 bool EventHandler::dragHysteresisExceeded(const IntPoint& dragViewportLocation)
const | |
| 1811 { | |
| 1812 IntPoint dragLocation = m_frame->view()->windowToContents(dragViewportLocati
on); | |
| 1813 IntSize delta = dragLocation - m_mouseDownPos; | |
| 1814 | |
| 1815 int threshold = GeneralDragHysteresis; | |
| 1816 if (dragState().m_dragSrcIsImage) | |
| 1817 threshold = ImageDragHysteresis; | |
| 1818 else if (dragState().m_dragSrcIsLink) | |
| 1819 threshold = LinkDragHysteresis; | |
| 1820 else if (dragState().m_dragSrcInSelection) | |
| 1821 threshold = TextDragHysteresis; | |
| 1822 | |
| 1823 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold; | |
| 1824 } | |
| 1825 | |
| 1826 void EventHandler::freeClipboard() | |
| 1827 { | |
| 1828 if (dragState().m_dragClipboard) | |
| 1829 dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb); | |
| 1830 } | |
| 1831 | |
| 1832 bool EventHandler::shouldDragAutoNode(Node* node, const IntPoint& point) const | |
| 1833 { | |
| 1834 ASSERT(node); | |
| 1835 if (node->hasChildNodes() || !m_frame->view()) | |
| 1836 return false; | |
| 1837 return m_frame->page() && m_frame->page()->dragController()->mayStartDragAtE
ventLocation(m_frame, point); | |
| 1838 } | |
| 1839 | |
| 1840 void EventHandler::dragSourceMovedTo(const PlatformMouseEvent& event) | |
| 1841 { | |
| 1842 if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) | |
| 1843 // for now we don't care if event handler cancels default behavior, sinc
e there is none | |
| 1844 dispatchDragSrcEvent(dragEvent, event); | |
| 1845 } | |
| 1846 | |
| 1847 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperat
ion operation) | |
| 1848 { | |
| 1849 if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) { | |
| 1850 dragState().m_dragClipboard->setDestinationOperation(operation); | |
| 1851 // for now we don't care if event handler cancels default behavior, sinc
e there is none | |
| 1852 dispatchDragSrcEvent(dragendEvent, event); | |
| 1853 } | |
| 1854 freeClipboard(); | |
| 1855 dragState().m_dragSrc = 0; | |
| 1856 } | |
| 1857 | |
| 1858 // returns if we should continue "default processing", i.e., whether eventhandle
r canceled | |
| 1859 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const Pla
tformMouseEvent& event) | |
| 1860 { | |
| 1861 return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dra
gState().m_dragClipboard.get()); | |
| 1862 } | |
| 1863 | |
| 1864 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event) | |
| 1865 { | |
| 1866 if (event.event().button() != LeftButton || event.event().eventType() != Mou
seEventMoved) { | |
| 1867 // If we allowed the other side of the bridge to handle a drag | |
| 1868 // last time, then m_mousePressed might still be set. So we | |
| 1869 // clear it now to make sure the next move after a drag | |
| 1870 // doesn't look like a drag. | |
| 1871 m_mousePressed = false; | |
| 1872 return false; | |
| 1873 } | |
| 1874 | |
| 1875 if (eventLoopHandleMouseDragged(event)) | |
| 1876 return true; | |
| 1877 | |
| 1878 // Careful that the drag starting logic stays in sync with eventMayStartDrag
() | |
| 1879 | |
| 1880 if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) { | |
| 1881 allowDHTMLDrag(dragState().m_dragSrcMayBeDHTML, dragState().m_dragSrcMay
BeUA); | |
| 1882 if (!dragState().m_dragSrcMayBeDHTML && !dragState().m_dragSrcMayBeUA) | |
| 1883 m_mouseDownMayStartDrag = false; // no element is draggable | |
| 1884 } | |
| 1885 | |
| 1886 if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) { | |
| 1887 // try to find an element that wants to be dragged | |
| 1888 HitTestRequest request(true, false); | |
| 1889 HitTestResult result(m_mouseDownPos); | |
| 1890 m_frame->contentRenderer()->layer()->hitTest(request, result); | |
| 1891 Node* node = result.innerNode(); | |
| 1892 if (node && node->renderer()) | |
| 1893 dragState().m_dragSrc = node->renderer()->draggableNode(dragState().
m_dragSrcMayBeDHTML, dragState().m_dragSrcMayBeUA, | |
| 1894 m_mouseDownP
os.x(), m_mouseDownPos.y(), dragState().m_dragSrcIsDHTML); | |
| 1895 else | |
| 1896 dragState().m_dragSrc = 0; | |
| 1897 | |
| 1898 if (!dragState().m_dragSrc) | |
| 1899 m_mouseDownMayStartDrag = false; // no element is draggable | |
| 1900 else { | |
| 1901 // remember some facts about this source, while we have a HitTestRes
ult handy | |
| 1902 node = result.URLElement(); | |
| 1903 dragState().m_dragSrcIsLink = node && node->isLink(); | |
| 1904 | |
| 1905 node = result.innerNonSharedNode(); | |
| 1906 dragState().m_dragSrcIsImage = node && node->renderer() && node->ren
derer()->isImage(); | |
| 1907 | |
| 1908 dragState().m_dragSrcInSelection = m_frame->selection()->contains(m_
mouseDownPos); | |
| 1909 } | |
| 1910 } | |
| 1911 | |
| 1912 // For drags starting in the selection, the user must wait between the mouse
down and mousedrag, | |
| 1913 // or else we bail on the dragging stuff and allow selection to occur | |
| 1914 if (m_mouseDownMayStartDrag && !dragState().m_dragSrcIsImage && dragState().
m_dragSrcInSelection && event.event().timestamp() - m_mouseDownTimestamp < TextD
ragDelay) { | |
| 1915 m_mouseDownMayStartDrag = false; | |
| 1916 dragState().m_dragSrc = 0; | |
| 1917 // ...but if this was the first click in the window, we don't even want
to start selection | |
| 1918 if (eventActivatedView(event.event())) | |
| 1919 m_mouseDownMayStartSelect = false; | |
| 1920 } | |
| 1921 | |
| 1922 if (!m_mouseDownMayStartDrag) | |
| 1923 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll; | |
| 1924 | |
| 1925 // We are starting a text/image/url drag, so the cursor should be an arrow | |
| 1926 m_frame->view()->setCursor(pointerCursor()); | |
| 1927 | |
| 1928 if (!dragHysteresisExceeded(event.event().pos())) | |
| 1929 return true; | |
| 1930 | |
| 1931 // Once we're past the hysteresis point, we don't want to treat this gesture
as a click | |
| 1932 invalidateClick(); | |
| 1933 | |
| 1934 DragOperation srcOp = DragOperationNone; | |
| 1935 | |
| 1936 freeClipboard(); // would only happen if we missed a dragEnd. Do it anyw
ay, just | |
| 1937 // to make sure it gets numbified | |
| 1938 dragState().m_dragClipboard = createDraggingClipboard(); | |
| 1939 | |
| 1940 if (dragState().m_dragSrcMayBeDHTML) { | |
| 1941 // Check to see if the is a DOM based drag, if it is get the DOM specifi
ed drag | |
| 1942 // image and offset | |
| 1943 if (dragState().m_dragSrcIsDHTML) { | |
| 1944 int srcX, srcY; | |
| 1945 if (RenderObject* renderer = dragState().m_dragSrc->renderer()) { | |
| 1946 renderer->absolutePosition(srcX, srcY); | |
| 1947 IntSize delta = m_mouseDownPos - IntPoint(srcX, srcY); | |
| 1948 dragState().m_dragClipboard->setDragImageElement(dragState().m_d
ragSrc.get(), IntPoint() + delta); | |
| 1949 } else { | |
| 1950 // The renderer has disappeared, this can happen if the onStartD
rag handler has hidden | |
| 1951 // the element in some way. In this case we just kill the drag. | |
| 1952 m_mouseDownMayStartDrag = false; | |
| 1953 goto cleanupDrag; | |
| 1954 } | |
| 1955 } | |
| 1956 | |
| 1957 m_mouseDownMayStartDrag = dispatchDragSrcEvent(dragstartEvent, m_mouseDo
wn) | |
| 1958 && !m_frame->selection()->isInPasswordField(); | |
| 1959 | |
| 1960 // Invalidate clipboard here against anymore pasteboard writing for secu
rity. The drag | |
| 1961 // image can still be changed as we drag, but not the pasteboard data. | |
| 1962 dragState().m_dragClipboard->setAccessPolicy(ClipboardImageWritable); | |
| 1963 | |
| 1964 if (m_mouseDownMayStartDrag) { | |
| 1965 // gather values from DHTML element, if it set any | |
| 1966 dragState().m_dragClipboard->sourceOperation(srcOp); | |
| 1967 | |
| 1968 // Yuck, dragSourceMovedTo() can be called as a result of kicking of
f the drag with | |
| 1969 // dragImage! Because of that dumb reentrancy, we may think we've n
ot started the | |
| 1970 // drag when that happens. So we have to assume it's started before
we kick it off. | |
| 1971 dragState().m_dragClipboard->setDragHasStarted(); | |
| 1972 } | |
| 1973 } | |
| 1974 | |
| 1975 if (m_mouseDownMayStartDrag) { | |
| 1976 DragController* dragController = m_frame->page() ? m_frame->page()->drag
Controller() : 0; | |
| 1977 bool startedDrag = dragController && dragController->startDrag(m_frame,
dragState().m_dragClipboard.get(), srcOp, event.event(), m_mouseDownPos, dragSta
te().m_dragSrcIsDHTML); | |
| 1978 if (!startedDrag && dragState().m_dragSrcMayBeDHTML) { | |
| 1979 // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND e
vent | |
| 1980 dispatchDragSrcEvent(dragendEvent, event.event()); | |
| 1981 m_mouseDownMayStartDrag = false; | |
| 1982 } | |
| 1983 } | |
| 1984 | |
| 1985 cleanupDrag: | |
| 1986 if (!m_mouseDownMayStartDrag) { | |
| 1987 // something failed to start the drag, cleanup | |
| 1988 freeClipboard(); | |
| 1989 dragState().m_dragSrc = 0; | |
| 1990 } | |
| 1991 | |
| 1992 // No more default handling (like selection), whether we're past the hystere
sis bounds or not | |
| 1993 return true; | |
| 1994 } | |
| 1995 | |
| 1996 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEve
nt, | |
| 1997 bool isLineBreak, bool isBackTab) | |
| 1998 { | |
| 1999 if (!m_frame) | |
| 2000 return false; | |
| 2001 #ifndef NDEBUG | |
| 2002 // Platforms should differentiate real commands like selectAll from text inp
ut in disguise (like insertNewline), | |
| 2003 // and avoid dispatching text input events from keydown default handlers. | |
| 2004 if (underlyingEvent && underlyingEvent->isKeyboardEvent()) | |
| 2005 ASSERT(static_cast<KeyboardEvent*>(underlyingEvent)->type() == keypressE
vent); | |
| 2006 #endif | |
| 2007 EventTarget* target; | |
| 2008 if (underlyingEvent) | |
| 2009 target = underlyingEvent->target(); | |
| 2010 else | |
| 2011 target = eventTargetNodeForDocument(m_frame->document()); | |
| 2012 if (!target) | |
| 2013 return false; | |
| 2014 RefPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text); | |
| 2015 event->setUnderlyingEvent(underlyingEvent); | |
| 2016 event->setIsLineBreak(isLineBreak); | |
| 2017 event->setIsBackTab(isBackTab); | |
| 2018 ExceptionCode ec; | |
| 2019 return target->dispatchEvent(event.release(), ec, true); | |
| 2020 } | |
| 2021 | |
| 2022 | |
| 2023 #if !PLATFORM(MAC) && !PLATFORM(QT) | |
| 2024 bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent*) const | |
| 2025 { | |
| 2026 return false; | |
| 2027 } | |
| 2028 #endif | |
| 2029 | |
| 2030 bool EventHandler::tabsToLinks(KeyboardEvent* event) const | |
| 2031 { | |
| 2032 Page* page = m_frame->page(); | |
| 2033 if (!page) | |
| 2034 return false; | |
| 2035 | |
| 2036 if (page->chrome()->client()->tabsToLinks()) | |
| 2037 return !invertSenseOfTabsToLinks(event); | |
| 2038 | |
| 2039 return invertSenseOfTabsToLinks(event); | |
| 2040 } | |
| 2041 | |
| 2042 void EventHandler::defaultTextInputEventHandler(TextEvent* event) | |
| 2043 { | |
| 2044 String data = event->data(); | |
| 2045 if (data == "\n") { | |
| 2046 if (event->isLineBreak()) { | |
| 2047 if (m_frame->editor()->insertLineBreak()) | |
| 2048 event->setDefaultHandled(); | |
| 2049 } else { | |
| 2050 if (m_frame->editor()->insertParagraphSeparator()) | |
| 2051 event->setDefaultHandled(); | |
| 2052 } | |
| 2053 } else { | |
| 2054 if (m_frame->editor()->insertTextWithoutSendingTextEvent(data, false, ev
ent)) | |
| 2055 event->setDefaultHandled(); | |
| 2056 } | |
| 2057 } | |
| 2058 | |
| 2059 void EventHandler::defaultTabEventHandler(KeyboardEvent* event) | |
| 2060 { | |
| 2061 // We should only advance focus on tabs if no special modifier keys are held
down. | |
| 2062 if (event->ctrlKey() || event->metaKey() || event->altGraphKey()) | |
| 2063 return; | |
| 2064 | |
| 2065 Page* page = m_frame->page(); | |
| 2066 if (!page) | |
| 2067 return; | |
| 2068 if (!page->tabKeyCyclesThroughElements()) | |
| 2069 return; | |
| 2070 | |
| 2071 FocusDirection focusDirection = event->shiftKey() ? FocusDirectionBackward :
FocusDirectionForward; | |
| 2072 | |
| 2073 // Tabs can be used in design mode editing. | |
| 2074 if (m_frame->document()->inDesignMode()) | |
| 2075 return; | |
| 2076 | |
| 2077 if (page->focusController()->advanceFocus(focusDirection, event)) | |
| 2078 event->setDefaultHandled(); | |
| 2079 } | |
| 2080 | |
| 2081 void EventHandler::capsLockStateMayHaveChanged() | |
| 2082 { | |
| 2083 if (Document* d = m_frame->document()) | |
| 2084 if (Node* node = d->focusedNode()) | |
| 2085 if (RenderObject* r = node->renderer()) | |
| 2086 r->capsLockStateMayHaveChanged(); | |
| 2087 } | |
| 2088 | |
| 2089 unsigned EventHandler::pendingFrameUnloadEventCount() | |
| 2090 { | |
| 2091 return m_pendingFrameUnloadEventCount; | |
| 2092 } | |
| 2093 | |
| 2094 void EventHandler::addPendingFrameUnloadEventCount() | |
| 2095 { | |
| 2096 m_pendingFrameUnloadEventCount += 1; | |
| 2097 m_frame->page()->changePendingUnloadEventCount(1); | |
| 2098 return; | |
| 2099 } | |
| 2100 | |
| 2101 void EventHandler::removePendingFrameUnloadEventCount() | |
| 2102 { | |
| 2103 ASSERT( (-1 + (int)m_pendingFrameUnloadEventCount) >= 0 ); | |
| 2104 m_pendingFrameUnloadEventCount -= 1; | |
| 2105 m_frame->page()->changePendingUnloadEventCount(-1); | |
| 2106 return; | |
| 2107 } | |
| 2108 | |
| 2109 void EventHandler::clearPendingFrameUnloadEventCount() | |
| 2110 { | |
| 2111 m_frame->page()->changePendingUnloadEventCount(-((int)m_pendingFrameUnloadEv
entCount)); | |
| 2112 m_pendingFrameUnloadEventCount = 0; | |
| 2113 return; | |
| 2114 } | |
| 2115 | |
| 2116 unsigned EventHandler::pendingFrameBeforeUnloadEventCount() | |
| 2117 { | |
| 2118 return m_pendingFrameBeforeUnloadEventCount; | |
| 2119 } | |
| 2120 | |
| 2121 void EventHandler::addPendingFrameBeforeUnloadEventCount() | |
| 2122 { | |
| 2123 m_pendingFrameBeforeUnloadEventCount += 1; | |
| 2124 m_frame->page()->changePendingBeforeUnloadEventCount(1); | |
| 2125 return; | |
| 2126 } | |
| 2127 | |
| 2128 void EventHandler::removePendingFrameBeforeUnloadEventCount() | |
| 2129 { | |
| 2130 ASSERT( (-1 + (int)m_pendingFrameBeforeUnloadEventCount) >= 0 ); | |
| 2131 m_pendingFrameBeforeUnloadEventCount -= 1; | |
| 2132 m_frame->page()->changePendingBeforeUnloadEventCount(-1); | |
| 2133 return; | |
| 2134 } | |
| 2135 | |
| 2136 void EventHandler::clearPendingFrameBeforeUnloadEventCount() | |
| 2137 { | |
| 2138 m_frame->page()->changePendingBeforeUnloadEventCount(-((int)m_pendingFrameBe
foreUnloadEventCount)); | |
| 2139 m_pendingFrameBeforeUnloadEventCount = 0; | |
| 2140 return; | |
| 2141 } | |
| 2142 } | |
| OLD | NEW |