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 |