[BlackBerry] Context menu cannot be invoked after doing text selection in landscape...
[WebKit-https.git] / Source / WebKit / blackberry / WebKitSupport / SelectionHandler.cpp
1 /*
2  * Copyright (C) 2010, 2011, 2012 Research In Motion Limited. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include "config.h"
20 #include "SelectionHandler.h"
21
22 #include "DOMSupport.h"
23 #include "Document.h"
24 #include "FatFingers.h"
25 #include "FloatQuad.h"
26 #include "Frame.h"
27 #include "FrameSelection.h"
28 #include "FrameView.h"
29 #include "HitTestResult.h"
30 #include "InputHandler.h"
31 #include "IntRect.h"
32 #include "SelectionOverlay.h"
33 #include "TouchEventHandler.h"
34 #include "WebPageClient.h"
35 #include "WebPage_p.h"
36
37 #include "htmlediting.h"
38 #include "visible_units.h"
39
40 #include <BlackBerryPlatformKeyboardEvent.h>
41 #include <BlackBerryPlatformLog.h>
42
43 #include <sys/keycodes.h>
44
45 // Note: This generates a lot of logs when dumping rects lists. It will seriously
46 // impact performance. Do not enable this during performance tests.
47 #define SHOWDEBUG_SELECTIONHANDLER 0
48 #define SHOWDEBUG_SELECTIONHANDLER_TIMING 0
49
50 using namespace BlackBerry::Platform;
51 using namespace WebCore;
52
53 #if SHOWDEBUG_SELECTIONHANDLER
54 #define SelectionLog(severity, format, ...) Platform::logAlways(severity, format, ## __VA_ARGS__)
55 #else
56 #define SelectionLog(severity, format, ...)
57 #endif // SHOWDEBUG_SELECTIONHANDLER
58
59 #if SHOWDEBUG_SELECTIONHANDLER_TIMING
60 #define SelectionTimingLog(severity, format, ...) Platform::logAlways(severity, format, ## __VA_ARGS__)
61 #else
62 #define SelectionTimingLog(severity, format, ...)
63 #endif // SHOWDEBUG_SELECTIONHANDLER_TIMING
64
65 namespace BlackBerry {
66 namespace WebKit {
67
68 SelectionHandler::SelectionHandler(WebPagePrivate* page)
69     : m_webPage(page)
70     , m_selectionActive(false)
71     , m_caretActive(false)
72     , m_lastUpdatedEndPointIsValid(false)
73     , m_didSuppressCaretPositionChangedNotification(false)
74 {
75 }
76
77 SelectionHandler::~SelectionHandler()
78 {
79 }
80
81 void SelectionHandler::cancelSelection()
82 {
83     m_selectionActive = false;
84     m_lastSelectionRegion = IntRectRegion();
85
86     if (m_webPage->m_selectionOverlay)
87         m_webPage->m_selectionOverlay->hide();
88     // Notify client with empty selection to ensure the handles are removed if
89     // rendering happened prior to processing on webkit thread
90     m_webPage->m_client->notifySelectionDetailsChanged(SelectionDetails());
91
92     SelectionLog(Platform::LogLevelInfo, "SelectionHandler::cancelSelection");
93
94     if (m_webPage->m_inputHandler->isInputMode())
95         m_webPage->m_inputHandler->cancelSelection();
96     else
97         m_webPage->focusedOrMainFrame()->selection()->clear();
98 }
99
100 BlackBerry::Platform::String SelectionHandler::selectedText() const
101 {
102     return m_webPage->focusedOrMainFrame()->editor()->selectedText();
103 }
104
105 WebCore::IntRect SelectionHandler::clippingRectForVisibleContent() const
106 {
107     // Get the containing content rect for the frame.
108     Frame* frame = m_webPage->focusedOrMainFrame();
109     WebCore::IntRect clipRect = WebCore::IntRect(WebCore::IntPoint(0, 0), frame->view()->contentsSize());
110     if (frame != m_webPage->mainFrame()) {
111         clipRect = m_webPage->getRecursiveVisibleWindowRect(frame->view(), true /* no clip to main frame window */);
112         clipRect = m_webPage->m_mainFrame->view()->windowToContents(clipRect);
113     }
114
115     // Get the input field containing box.
116     WebCore::IntRect inputBoundingBox = m_webPage->m_inputHandler->boundingBoxForInputField();
117     if (!inputBoundingBox.isEmpty()) {
118         // Adjust the bounding box to the frame offset.
119         inputBoundingBox = m_webPage->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(inputBoundingBox));
120         clipRect.intersect(inputBoundingBox);
121     }
122     return clipRect;
123 }
124
125 void SelectionHandler::regionForTextQuads(Vector<FloatQuad> &quadList, IntRectRegion& region, bool shouldClipToVisibleContent) const
126 {
127     ASSERT(region.isEmpty());
128
129     if (!quadList.isEmpty()) {
130         FrameView* frameView = m_webPage->focusedOrMainFrame()->view();
131
132         // frameRect is in frame coordinates.
133         WebCore::IntRect frameRect(WebCore::IntPoint(0, 0), frameView->contentsSize());
134
135         // framePosition is in main frame coordinates.
136         WebCore::IntPoint framePosition = m_webPage->frameOffset(m_webPage->focusedOrMainFrame());
137
138         // Get the visibile content rect.
139         WebCore::IntRect clippingRect = shouldClipToVisibleContent ? clippingRectForVisibleContent() : WebCore::IntRect(-1, -1, 0, 0);
140
141         // Convert the text quads into a more platform friendy
142         // IntRectRegion and adjust for subframes.
143         Platform::IntRect selectionBoundingBox;
144         std::vector<Platform::IntRect> adjustedIntRects;
145         for (unsigned i = 0; i < quadList.size(); i++) {
146             WebCore::IntRect enclosingRect = quadList[i].enclosingBoundingBox();
147             enclosingRect.intersect(frameRect);
148             enclosingRect.move(framePosition.x(), framePosition.y());
149
150             // Clip to the visible content.
151             if (clippingRect.location() != DOMSupport::InvalidPoint)
152                 enclosingRect.intersect(clippingRect);
153
154             adjustedIntRects.push_back(enclosingRect);
155             selectionBoundingBox = unionOfRects(enclosingRect, selectionBoundingBox);
156         }
157         region = IntRectRegion(selectionBoundingBox, adjustedIntRects.size(), adjustedIntRects);
158     }
159 }
160
161 static VisiblePosition visiblePositionForPointIgnoringClipping(const Frame& frame, const WebCore::IntPoint& framePoint)
162 {
163     // Frame::visiblePositionAtPoint hard-codes ignoreClipping=false in the
164     // call to hitTestResultAtPoint. This has a bug where some pages (such as
165     // metafilter) will return the wrong VisiblePosition for points that are
166     // outside the visible rect. To work around the bug, this is a copy of
167     // visiblePositionAtPoint which which passes ignoreClipping=true.
168     // See RIM Bug #4315.
169     HitTestResult result = frame.eventHandler()->hitTestResultAtPoint(framePoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::AllowShadowContent | HitTestRequest::IgnoreClipping);
170
171     Node* node = result.innerNode();
172     if (!node || node->document() != frame.document())
173         return VisiblePosition();
174
175     RenderObject* renderer = node->renderer();
176     if (!renderer)
177         return VisiblePosition();
178
179     VisiblePosition visiblePos = renderer->positionForPoint(result.localPoint());
180     if (visiblePos.isNull())
181         visiblePos = VisiblePosition(Position(createLegacyEditingPosition(node, 0)));
182
183     return visiblePos;
184 }
185
186 static unsigned directionOfPointRelativeToRect(const WebCore::IntPoint& point, const WebCore::IntRect& rect, const bool useTopPadding = true, const bool useBottomPadding = true)
187 {
188     ASSERT(!rect.contains(point));
189
190     // Padding to prevent accidental trigger of up/down when intending to do horizontal movement.
191     const int verticalPadding = 5;
192
193     // Do height movement check first but add padding. We may be off on both x & y axis and only
194     // want to move in one direction at a time.
195     if (point.y() - (useTopPadding ? verticalPadding : 0) < rect.y())
196         return KEYCODE_UP;
197     if (point.y() > rect.maxY() + (useBottomPadding ? verticalPadding : 0))
198         return KEYCODE_DOWN;
199     if (point.x() < rect.location().x())
200         return KEYCODE_LEFT;
201     if (point.x() > rect.maxX())
202         return KEYCODE_RIGHT;
203
204     return 0;
205 }
206
207 bool SelectionHandler::shouldUpdateSelectionOrCaretForPoint(const WebCore::IntPoint& point, const WebCore::IntRect& caretRect, bool startCaret) const
208 {
209     ASSERT(m_webPage->m_inputHandler->isInputMode());
210
211     // If the point isn't valid don't block change as it is not actually changing.
212     if (point == DOMSupport::InvalidPoint)
213         return true;
214
215     VisibleSelection currentSelection = m_webPage->focusedOrMainFrame()->selection()->selection();
216
217     // If the input field is single line or we are on the first or last
218     // line of a multiline input field only horizontal movement is supported.
219     bool aboveCaret = point.y() < caretRect.y();
220     bool belowCaret = point.y() >= caretRect.maxY();
221
222     SelectionLog(Platform::LogLevelInfo,
223         "SelectionHandler::shouldUpdateSelectionOrCaretForPoint multiline = %s above = %s below = %s first line = %s last line = %s start = %s",
224         m_webPage->m_inputHandler->isMultilineInputMode() ? "true" : "false",
225         aboveCaret ? "true" : "false",
226         belowCaret ? "true" : "false",
227         inSameLine(currentSelection.visibleStart(), startOfEditableContent(currentSelection.visibleStart())) ? "true" : "false",
228         inSameLine(currentSelection.visibleEnd(), endOfEditableContent(currentSelection.visibleEnd())) ? "true" : "false",
229         startCaret ? "true" : "false");
230
231     if (!m_webPage->m_inputHandler->isMultilineInputMode() && (aboveCaret || belowCaret))
232         return false;
233     if (startCaret && inSameLine(currentSelection.visibleStart(), startOfEditableContent(currentSelection.visibleStart())) && aboveCaret)
234         return false;
235     if (!startCaret && inSameLine(currentSelection.visibleEnd(), endOfEditableContent(currentSelection.visibleEnd())) && belowCaret)
236         return false;
237
238     return true;
239 }
240
241 void SelectionHandler::setCaretPosition(const WebCore::IntPoint& position)
242 {
243     if (!m_webPage->m_inputHandler->isInputMode() || !m_webPage->focusedOrMainFrame()->document()->focusedNode())
244         return;
245
246     m_caretActive = true;
247
248     SelectionLog(Platform::LogLevelInfo,
249         "SelectionHandler::setCaretPosition requested point %s",
250         Platform::IntPoint(position).toString().c_str());
251
252     Frame* focusedFrame = m_webPage->focusedOrMainFrame();
253     FrameSelection* controller = focusedFrame->selection();
254     WebCore::IntPoint relativePoint = DOMSupport::convertPointToFrame(m_webPage->mainFrame(), focusedFrame, position);
255     WebCore::IntRect currentCaretRect = controller->selection().visibleStart().absoluteCaretBounds();
256
257     if (relativePoint == DOMSupport::InvalidPoint || !shouldUpdateSelectionOrCaretForPoint(relativePoint, currentCaretRect)) {
258         selectionPositionChanged(true /* forceUpdateWithoutChange */);
259         return;
260     }
261
262     VisiblePosition visibleCaretPosition(focusedFrame->visiblePositionForPoint(relativePoint));
263
264     if (RenderObject* focusedRenderer = focusedFrame->document()->focusedNode()->renderer()) {
265         WebCore::IntRect nodeOutlineBounds(focusedRenderer->absoluteOutlineBounds());
266         if (!nodeOutlineBounds.contains(relativePoint)) {
267             if (unsigned character = directionOfPointRelativeToRect(relativePoint, currentCaretRect))
268                 m_webPage->m_inputHandler->handleKeyboardInput(Platform::KeyboardEvent(character));
269
270             // Send the selection changed in case this does not trigger a selection change to
271             // ensure the caret position is accurate. This may be a duplicate event.
272             selectionPositionChanged(true /* forceUpdateWithoutChange */);
273             return;
274         }
275     }
276
277     VisibleSelection newSelection(visibleCaretPosition);
278     if (controller->selection() == newSelection) {
279         selectionPositionChanged(true /* forceUpdateWithoutChange */);
280         return;
281     }
282
283     controller->setSelection(newSelection);
284
285     SelectionLog(Platform::LogLevelInfo, "SelectionHandler::setCaretPosition point valid, cursor updated");
286 }
287
288 void SelectionHandler::inputHandlerDidFinishProcessingChange()
289 {
290     if (m_didSuppressCaretPositionChangedNotification)
291         notifyCaretPositionChangedIfNeeded(false);
292 }
293
294 // This function makes sure we are not reducing the selection to a caret selection.
295 static bool shouldExtendSelectionInDirection(const VisibleSelection& selection, unsigned character)
296 {
297     FrameSelection tempSelection;
298     tempSelection.setSelection(selection);
299     switch (character) {
300     case KEYCODE_LEFT:
301         tempSelection.modify(FrameSelection::AlterationExtend, DirectionLeft, CharacterGranularity);
302         break;
303     case KEYCODE_RIGHT:
304         tempSelection.modify(FrameSelection::AlterationExtend, DirectionRight, CharacterGranularity);
305         break;
306     case KEYCODE_UP:
307         tempSelection.modify(FrameSelection::AlterationExtend, DirectionBackward, LineGranularity);
308         break;
309     case KEYCODE_DOWN:
310         tempSelection.modify(FrameSelection::AlterationExtend, DirectionForward, LineGranularity);
311         break;
312     default:
313         break;
314     }
315
316     if ((character == KEYCODE_LEFT || character == KEYCODE_RIGHT)
317         && (!inSameLine(selection.visibleStart(), tempSelection.selection().visibleStart())
318            || !inSameLine(selection.visibleEnd(), tempSelection.selection().visibleEnd())))
319         return false;
320
321     return tempSelection.selection().selectionType() == VisibleSelection::RangeSelection;
322 }
323
324 static int clamp(const int min, const int value, const int max)
325 {
326     return value < min ? min : std::min(value, max);
327 }
328
329 static VisiblePosition directionalVisiblePositionAtExtentOfBox(Frame* frame, const WebCore::IntRect& boundingBox, unsigned direction, const WebCore::IntPoint& basePoint)
330 {
331     ASSERT(frame);
332
333     if (!frame)
334         return VisiblePosition();
335
336     switch (direction) {
337     case KEYCODE_LEFT:
338         // Extend x to start and clamp y to the edge of bounding box.
339         return frame->visiblePositionForPoint(WebCore::IntPoint(boundingBox.x(), clamp(boundingBox.y(), basePoint.y(), boundingBox.maxY())));
340     case KEYCODE_RIGHT:
341         // Extend x to end and clamp y to the edge of bounding box.
342         return frame->visiblePositionForPoint(WebCore::IntPoint(boundingBox.maxX(), clamp(boundingBox.y(), basePoint.y(), boundingBox.maxY())));
343     case KEYCODE_UP:
344         // Extend y to top and clamp x to the edge of bounding box.
345         return frame->visiblePositionForPoint(WebCore::IntPoint(clamp(boundingBox.x(), basePoint.x(), boundingBox.maxX()), boundingBox.y()));
346     case KEYCODE_DOWN:
347         // Extend y to bottom and clamp x to the edge of bounding box.
348         return frame->visiblePositionForPoint(WebCore::IntPoint(clamp(boundingBox.x(), basePoint.x(), boundingBox.maxX()), boundingBox.maxY()));
349     default:
350         break;
351     }
352
353     return frame->visiblePositionForPoint(WebCore::IntPoint(basePoint.x(), basePoint.y()));
354 }
355
356 static bool pointIsOutsideOfBoundingBoxInDirection(unsigned direction, const WebCore::IntPoint& selectionPoint, const WebCore::IntRect& boundingBox)
357 {
358     if ((direction == KEYCODE_LEFT && selectionPoint.x() < boundingBox.x())
359         || (direction == KEYCODE_UP && selectionPoint.y() < boundingBox.y())
360         || (direction == KEYCODE_RIGHT && selectionPoint.x() > boundingBox.maxX())
361         || (direction == KEYCODE_DOWN && selectionPoint.y() > boundingBox.maxY()))
362         return true;
363
364     return false;
365 }
366
367 unsigned SelectionHandler::extendSelectionToFieldBoundary(bool isStartHandle, const WebCore::IntPoint& selectionPoint, VisibleSelection& newSelection)
368 {
369     Frame* focusedFrame = m_webPage->focusedOrMainFrame();
370     if (!focusedFrame->document()->focusedNode() || !focusedFrame->document()->focusedNode()->renderer())
371         return 0;
372
373     FrameSelection* controller = focusedFrame->selection();
374
375     WebCore::IntRect caretRect = isStartHandle ? controller->selection().visibleStart().absoluteCaretBounds()
376                                       : controller->selection().visibleEnd().absoluteCaretBounds();
377
378     WebCore::IntRect nodeBoundingBox = focusedFrame->document()->focusedNode()->renderer()->absoluteBoundingBoxRect();
379     nodeBoundingBox.inflate(-1);
380
381     // Start handle is outside of the field. Treat it as the changed handle and move
382     // relative to the start caret rect.
383     unsigned character = directionOfPointRelativeToRect(selectionPoint, caretRect, isStartHandle /* useTopPadding */, !isStartHandle /* useBottomPadding */);
384
385     // Prevent incorrect movement, handles can only extend the selection this way
386     // to prevent inversion of the handles.
387     if (isStartHandle && (character == KEYCODE_RIGHT || character == KEYCODE_DOWN)
388         || !isStartHandle && (character == KEYCODE_LEFT || character == KEYCODE_UP))
389         character = 0;
390
391     VisiblePosition newVisiblePosition = isStartHandle ? controller->selection().extent() : controller->selection().base();
392     // Extend the selection to the bounds of the box before doing incremental scroll if the point is outside the node.
393     // Don't extend selection and handle the character at the same time.
394     if (pointIsOutsideOfBoundingBoxInDirection(character, selectionPoint, nodeBoundingBox))
395         newVisiblePosition = directionalVisiblePositionAtExtentOfBox(focusedFrame, nodeBoundingBox, character, selectionPoint);
396
397     if (isStartHandle)
398         newSelection = VisibleSelection(newVisiblePosition, newSelection.extent(), true /* isDirectional */);
399     else
400         newSelection = VisibleSelection(newSelection.base(), newVisiblePosition, true /* isDirectional */);
401
402     // If no selection will be changed, return the character to extend using navigation.
403     if (controller->selection() == newSelection)
404         return character;
405
406     // Selection has been updated.
407     return 0;
408 }
409
410 // Returns true if handled.
411 bool SelectionHandler::updateOrHandleInputSelection(VisibleSelection& newSelection, const WebCore::IntPoint& relativeStart
412                                                     , const WebCore::IntPoint& relativeEnd)
413 {
414     ASSERT(m_webPage->m_inputHandler->isInputMode());
415
416     Frame* focusedFrame = m_webPage->focusedOrMainFrame();
417     Node* focusedNode = focusedFrame->document()->focusedNode();
418     if (!focusedNode || !focusedNode->renderer())
419         return false;
420
421     FrameSelection* controller = focusedFrame->selection();
422
423     WebCore::IntRect currentStartCaretRect = controller->selection().visibleStart().absoluteCaretBounds();
424     WebCore::IntRect currentEndCaretRect = controller->selection().visibleEnd().absoluteCaretBounds();
425
426     // Check if the handle movement is valid.
427     if (!shouldUpdateSelectionOrCaretForPoint(relativeStart, currentStartCaretRect, true /* startCaret */)
428         || !shouldUpdateSelectionOrCaretForPoint(relativeEnd, currentEndCaretRect, false /* startCaret */)) {
429         selectionPositionChanged(true /* forceUpdateWithoutChange */);
430         return true;
431     }
432
433     WebCore::IntRect nodeBoundingBox = focusedNode->renderer()->absoluteBoundingBoxRect();
434
435     // Only do special handling if one handle is outside of the node.
436     bool startIsOutsideOfField = relativeStart != DOMSupport::InvalidPoint && !nodeBoundingBox.contains(relativeStart);
437     bool endIsOutsideOfField = relativeEnd != DOMSupport::InvalidPoint && !nodeBoundingBox.contains(relativeEnd);
438     if (startIsOutsideOfField && endIsOutsideOfField)
439         return false;
440
441     unsigned character = 0;
442     if (startIsOutsideOfField) {
443         character = extendSelectionToFieldBoundary(true /* isStartHandle */, relativeStart, newSelection);
444         if (character) {
445             // Invert the selection so that the cursor point is at the beginning.
446             controller->setSelection(VisibleSelection(controller->selection().end(), controller->selection().start(), true /* isDirectional */));
447         }
448     } else if (endIsOutsideOfField) {
449         character = extendSelectionToFieldBoundary(false /* isStartHandle */, relativeEnd, newSelection);
450         if (character) {
451             // Reset the selection so that the end is the edit point.
452             controller->setSelection(VisibleSelection(controller->selection().start(), controller->selection().end(), true /* isDirectional */));
453         }
454     }
455
456     if (!character)
457         return false;
458
459     SelectionLog(Platform::LogLevelInfo,
460         "SelectionHandler::updateOrHandleInputSelection making selection change attempt using key event %d",
461         character);
462
463     if (shouldExtendSelectionInDirection(controller->selection(), character))
464         m_webPage->m_inputHandler->handleKeyboardInput(Platform::KeyboardEvent(character, Platform::KeyboardEvent::KeyDown, KEYMOD_SHIFT));
465
466     // Send the selection changed in case this does not trigger a selection change to
467     // ensure the caret position is accurate. This may be a duplicate event.
468     selectionPositionChanged(true /* forceUpdateWithoutChange */);
469     return true;
470 }
471
472 void SelectionHandler::setSelection(const WebCore::IntPoint& start, const WebCore::IntPoint& end)
473 {
474     m_selectionActive = true;
475
476     ASSERT(m_webPage);
477     ASSERT(m_webPage->focusedOrMainFrame());
478     ASSERT(m_webPage->focusedOrMainFrame()->selection());
479
480     Frame* focusedFrame = m_webPage->focusedOrMainFrame();
481     FrameSelection* controller = focusedFrame->selection();
482
483 #if SHOWDEBUG_SELECTIONHANDLER_TIMING
484     m_timer.start();
485 #endif
486
487     SelectionLog(Platform::LogLevelInfo,
488         "SelectionHandler::setSelection adjusted points %s, %s",
489         Platform::IntPoint(start).toString().c_str(),
490         Platform::IntPoint(end).toString().c_str());
491
492     // Note that IntPoint(-1, -1) is being our sentinel so far for
493     // clipped out selection starting or ending location.
494     bool startIsValid = start != DOMSupport::InvalidPoint;
495     m_lastUpdatedEndPointIsValid = end != DOMSupport::InvalidPoint;
496
497     // At least one of the locations must be valid.
498     ASSERT(startIsValid || m_lastUpdatedEndPointIsValid);
499
500     WebCore::IntPoint relativeStart = start;
501     WebCore::IntPoint relativeEnd = end;
502
503     VisibleSelection newSelection(controller->selection());
504
505     // We need the selection to be ordered base then extent.
506     if (!controller->selection().isBaseFirst())
507         controller->setSelection(VisibleSelection(controller->selection().start(), controller->selection().end(), true /* isDirectional */));
508
509     // We don't return early in the following, so that we can do input field scrolling if the
510     // handle is outside the bounds of the field. This can be extended to handle sub-region
511     // scrolling as well
512     if (startIsValid) {
513         relativeStart = DOMSupport::convertPointToFrame(m_webPage->mainFrame(), focusedFrame, start);
514
515         VisiblePosition base = visiblePositionForPointIgnoringClipping(*focusedFrame, clipPointToVisibleContainer(start));
516         if (base.isNotNull()) {
517             // The function setBase validates the "base"
518             newSelection.setBase(base);
519             newSelection.setWithoutValidation(newSelection.base(), controller->selection().end());
520             // Don't return early.
521         }
522     }
523
524     if (m_lastUpdatedEndPointIsValid) {
525         relativeEnd = DOMSupport::convertPointToFrame(m_webPage->mainFrame(), focusedFrame, end);
526
527         VisiblePosition extent = visiblePositionForPointIgnoringClipping(*focusedFrame, clipPointToVisibleContainer(end));
528         if (extent.isNotNull()) {
529             // The function setExtent validates the "extent"
530             newSelection.setExtent(extent);
531             newSelection.setWithoutValidation(controller->selection().start(), newSelection.extent());
532             // Don't return early.
533         }
534     }
535
536     newSelection.setIsDirectional(true);
537
538     if (m_webPage->m_inputHandler->isInputMode()) {
539         if (updateOrHandleInputSelection(newSelection, relativeStart, relativeEnd))
540             return;
541     }
542
543     if (controller->selection() == newSelection) {
544         selectionPositionChanged(true /* forceUpdateWithoutChange */);
545         return;
546     }
547
548     // If the selection size is reduce to less than a character, selection type becomes
549     // Caret. As long as it is still a range, it's a valid selection. Selection cannot
550     // be cancelled through this function.
551     Vector<FloatQuad> quads;
552     DOMSupport::visibleTextQuads(newSelection, quads);
553
554     IntRectRegion unclippedRegion;
555     regionForTextQuads(quads, unclippedRegion, false /* shouldClipToVisibleContent */);
556
557     if (unclippedRegion.isEmpty()) {
558         // Requested selection results in an empty selection, skip this change.
559         selectionPositionChanged(true /* forceUpdateWithoutChange */);
560
561         SelectionLog(Platform::LogLevelWarn, "SelectionHandler::setSelection selection points invalid, selection not updated.");
562         return;
563     }
564
565     // Check if the handles reversed position.
566     if (m_selectionActive && !newSelection.isBaseFirst())
567         m_webPage->m_client->notifySelectionHandlesReversed();
568
569     controller->setSelection(newSelection);
570     SelectionLog(Platform::LogLevelInfo, "SelectionHandler::setSelection selection points valid, selection updated.");
571 }
572
573 // FIXME re-use this in context. Must be updated to include an option to return the href.
574 // This function should be moved to a new unit file. Names suggetions include DOMQueries
575 // and NodeTypes. Functions currently in InputHandler.cpp, SelectionHandler.cpp and WebPage.cpp
576 // can all be moved in.
577 static Node* enclosingLinkEventParentForNode(Node* node)
578 {
579     if (!node)
580         return 0;
581
582     Node* linkNode = node->enclosingLinkEventParentOrSelf();
583     return linkNode && linkNode->isLink() ? linkNode : 0;
584 }
585
586 bool SelectionHandler::selectNodeIfFatFingersResultIsLink(FatFingersResult fatFingersResult)
587 {
588     if (!fatFingersResult.isValid())
589         return false;
590     Node* targetNode = fatFingersResult.node(FatFingersResult::ShadowContentNotAllowed);
591     ASSERT(targetNode);
592     // If the node at the point is a link, focus on the entire link, not a word.
593     if (Node* link = enclosingLinkEventParentForNode(targetNode)) {
594         selectObject(link);
595         return true;
596     }
597     return false;
598 }
599
600 void SelectionHandler::selectAtPoint(const WebCore::IntPoint& location)
601 {
602     // If point is invalid trigger selection based expansion.
603     if (location == DOMSupport::InvalidPoint) {
604         selectObject(WordGranularity);
605         return;
606     }
607
608     WebCore::IntPoint targetPosition;
609     // FIXME: Factory this get right fat finger code into a helper.
610     const FatFingersResult lastFatFingersResult = m_webPage->m_touchEventHandler->lastFatFingersResult();
611     if (selectNodeIfFatFingersResultIsLink(lastFatFingersResult))
612         return;
613
614     if (lastFatFingersResult.resultMatches(location, FatFingers::Text) && lastFatFingersResult.positionWasAdjusted() && lastFatFingersResult.nodeAsElementIfApplicable()) {
615         targetNode = lastFatFingersResult.node(FatFingersResult::ShadowContentNotAllowed);
616         targetPosition = lastFatFingersResult.adjustedPosition();
617     } else {
618         FatFingersResult newFatFingersResult = FatFingers(m_webPage, location, FatFingers::Text).findBestPoint();
619         if (!newFatFingersResult.positionWasAdjusted())
620             return;
621
622         if (selectNodeIfFatFingersResultIsLink(newFatFingersResult))
623             return;
624
625         targetPosition = newFatFingersResult.adjustedPosition();
626     }
627
628     // selectAtPoint API currently only supports WordGranularity but may be extended in the future.
629     selectObject(targetPosition, WordGranularity);
630 }
631
632 static bool expandSelectionToGranularity(Frame* frame, VisibleSelection selection, TextGranularity granularity, bool isInputMode)
633 {
634     ASSERT(frame);
635     ASSERT(frame->selection());
636
637     if (!(selection.start().anchorNode() && selection.start().anchorNode()->isTextNode()))
638         return false;
639
640     if (granularity == WordGranularity)
641         selection = DOMSupport::visibleSelectionForClosestActualWordStart(selection);
642
643     selection.expandUsingGranularity(granularity);
644     selection.setAffinity(frame->selection()->affinity());
645
646     if (isInputMode && !frame->selection()->shouldChangeSelection(selection))
647         return false;
648
649     frame->selection()->setSelection(selection);
650     return true;
651 }
652
653 void SelectionHandler::selectObject(const WebCore::IntPoint& location, TextGranularity granularity)
654 {
655     ASSERT(location.x() >= 0 && location.y() >= 0);
656     ASSERT(m_webPage && m_webPage->focusedOrMainFrame() && m_webPage->focusedOrMainFrame()->selection());
657     Frame* focusedFrame = m_webPage->focusedOrMainFrame();
658
659     SelectionLog(Platform::LogLevelInfo,
660         "SelectionHandler::selectObject adjusted points %s",
661         Platform::IntPoint(location).toString().c_str());
662
663     WebCore::IntPoint relativePoint = DOMSupport::convertPointToFrame(m_webPage->mainFrame(), focusedFrame, location);
664     // Clear input focus if we're not selecting in old input field.
665     if (!m_webPage->m_inputHandler->boundingBoxForInputField().contains(relativePoint))
666         m_webPage->clearFocusNode();
667
668     VisiblePosition pointLocation(focusedFrame->visiblePositionForPoint(relativePoint));
669     VisibleSelection selection = VisibleSelection(pointLocation, pointLocation);
670
671     m_selectionActive = expandSelectionToGranularity(focusedFrame, selection, granularity, m_webPage->m_inputHandler->isInputMode());
672 }
673
674 void SelectionHandler::selectObject(TextGranularity granularity)
675 {
676     ASSERT(m_webPage && m_webPage->m_inputHandler);
677     // Using caret location, must be inside an input field.
678     if (!m_webPage->m_inputHandler->isInputMode())
679         return;
680
681     ASSERT(m_webPage->focusedOrMainFrame() && m_webPage->focusedOrMainFrame()->selection());
682     Frame* focusedFrame = m_webPage->focusedOrMainFrame();
683
684     SelectionLog(Platform::LogLevelInfo, "SelectionHandler::selectObject using current selection");
685
686     ASSERT(focusedFrame->selection()->selectionType() != VisibleSelection::NoSelection);
687
688     // Use the current selection as the selection point.
689     VisibleSelection selectionOrigin = focusedFrame->selection()->selection();
690
691     // If this is the end of the input field, make sure we select the last word.
692     if (m_webPage->m_inputHandler->isCaretAtEndOfText())
693         selectionOrigin = previousWordPosition(selectionOrigin.start());
694
695     m_selectionActive = expandSelectionToGranularity(focusedFrame, selectionOrigin, granularity, true /* isInputMode */);
696 }
697
698 void SelectionHandler::selectObject(Node* node)
699 {
700     if (!node)
701         return;
702
703     // Clear input focus if we're not selecting text there.
704     if (node != m_webPage->m_inputHandler->currentFocusElement().get())
705         m_webPage->clearFocusNode();
706
707     m_selectionActive = true;
708
709     ASSERT(m_webPage && m_webPage->focusedOrMainFrame() && m_webPage->focusedOrMainFrame()->selection());
710     Frame* focusedFrame = m_webPage->focusedOrMainFrame();
711
712     SelectionLog(Platform::LogLevelInfo, "SelectionHandler::selectNode");
713
714     VisibleSelection selection = VisibleSelection::selectionFromContentsOfNode(node);
715     focusedFrame->selection()->setSelection(selection);
716 }
717
718 static TextDirection directionOfEnclosingBlock(FrameSelection* selection)
719 {
720     Node* enclosingBlockNode = enclosingBlock(selection->selection().extent().deprecatedNode());
721     if (!enclosingBlockNode)
722         return LTR;
723
724     if (RenderObject* renderer = enclosingBlockNode->renderer())
725         return renderer->style()->direction();
726
727     return LTR;
728 }
729
730 // Returns > 0 if p1 is "closer" to referencePoint, < 0 if p2 is "closer", 0 if they are equidistant.
731 // Because text is usually arranged in horizontal rows, distance is measured along the y-axis, with x-axis used only to break ties.
732 // If rightGravity is true, the right-most x-coordinate is chosen, otherwise teh left-most coordinate is chosen.
733 static inline int comparePointsToReferencePoint(const WebCore::IntPoint& p1, const WebCore::IntPoint& p2, const WebCore::IntPoint& referencePoint, bool rightGravity)
734 {
735     int dy1 = abs(referencePoint.y() - p1.y());
736     int dy2 = abs(referencePoint.y() - p2.y());
737     if (dy1 != dy2)
738         return dy2 - dy1;
739
740     // Same y-coordinate, choose the farthest right (or left) point.
741     if (p1.x() == p2.x())
742         return 0;
743
744     if (p1.x() > p2.x())
745         return rightGravity ? 1 : -1;
746
747     return rightGravity ? -1 : 1;
748 }
749
750 // NOTE/FIXME: Due to r77286, we are getting off-by-one results in the IntRect class counterpart implementation of the
751 //             methods below. As done in r89803, r77928 and a few others, lets use local method to fix it.
752 //             We should keep our eyes very open on it, since it can affect BackingStore very badly.
753 static WebCore::IntPoint minXMinYCorner(const WebCore::IntRect& rect) { return rect.location(); } // typically topLeft
754 static WebCore::IntPoint maxXMinYCorner(const WebCore::IntRect& rect) { return WebCore::IntPoint(rect.x() + rect.width() - 1, rect.y()); } // typically topRight
755 static WebCore::IntPoint minXMaxYCorner(const WebCore::IntRect& rect) { return WebCore::IntPoint(rect.x(), rect.y() + rect.height() - 1); } // typically bottomLeft
756 static WebCore::IntPoint maxXMaxYCorner(const WebCore::IntRect& rect) { return WebCore::IntPoint(rect.x() + rect.width() - 1, rect.y() + rect.height() - 1); } // typically bottomRight
757
758 // The caret is a one-pixel wide line down either the right or left edge of a
759 // rect, depending on the text direction.
760 static inline bool caretIsOnLeft(bool isStartCaret, bool isRTL)
761 {
762     if (isStartCaret)
763         return !isRTL;
764
765     return isRTL;
766 }
767
768 static inline WebCore::IntPoint caretLocationForRect(const WebCore::IntRect& rect, bool isStartCaret, bool isRTL)
769 {
770     return caretIsOnLeft(isStartCaret, isRTL) ? minXMinYCorner(rect) : maxXMinYCorner(rect);
771 }
772
773 static inline WebCore::IntPoint caretComparisonPointForRect(const WebCore::IntRect& rect, bool isStartCaret, bool isRTL)
774 {
775     if (isStartCaret)
776         return caretIsOnLeft(isStartCaret, isRTL) ? minXMinYCorner(rect) : maxXMinYCorner(rect);
777
778     return caretIsOnLeft(isStartCaret, isRTL) ? minXMaxYCorner(rect) : maxXMaxYCorner(rect);
779 }
780
781 static void adjustCaretRects(WebCore::IntRect& startCaret, bool isStartCaretClippedOut,
782                              WebCore::IntRect& endCaret, bool isEndCaretClippedOut,
783                              const std::vector<Platform::IntRect> rectList,
784                              const WebCore::IntPoint& startReferencePoint,
785                              const WebCore::IntPoint& endReferencePoint,
786                              bool isRTL)
787 {
788     // startReferencePoint is the best guess at the top left of the selection; endReferencePoint is the best guess at the bottom right.
789     if (isStartCaretClippedOut)
790         startCaret.setLocation(DOMSupport::InvalidPoint);
791     else {
792         startCaret = rectList[0];
793         startCaret.setLocation(caretLocationForRect(startCaret, true, isRTL));
794         // Reset width to 1 as we are strictly interested in caret location.
795         startCaret.setWidth(1);
796     }
797
798     if (isEndCaretClippedOut)
799         endCaret.setLocation(DOMSupport::InvalidPoint);
800     else {
801         endCaret = rectList[0];
802         endCaret.setLocation(caretLocationForRect(endCaret, false, isRTL));
803         // Reset width to 1 as we are strictly interested in caret location.
804         endCaret.setWidth(1);
805     }
806
807     if (isStartCaretClippedOut && isEndCaretClippedOut)
808         return;
809
810     for (unsigned i = 1; i < rectList.size(); i++) {
811         WebCore::IntRect currentRect(rectList[i]);
812
813         // Compare and update the start and end carets with their respective reference points.
814         if (!isStartCaretClippedOut && comparePointsToReferencePoint(
815                     caretComparisonPointForRect(currentRect, true, isRTL),
816                     caretComparisonPointForRect(startCaret, true, isRTL),
817                     startReferencePoint, isRTL) > 0) {
818             startCaret.setLocation(caretLocationForRect(currentRect, true, isRTL));
819             startCaret.setHeight(currentRect.height());
820         }
821
822         if (!isEndCaretClippedOut && comparePointsToReferencePoint(
823                     caretComparisonPointForRect(currentRect, false, isRTL),
824                     caretComparisonPointForRect(endCaret, false, isRTL),
825                     endReferencePoint, !isRTL) > 0) {
826             endCaret.setLocation(caretLocationForRect(currentRect, false, isRTL));
827             endCaret.setHeight(currentRect.height());
828         }
829     }
830 }
831
832 WebCore::IntPoint SelectionHandler::clipPointToVisibleContainer(const WebCore::IntPoint& point) const
833 {
834     ASSERT(m_webPage->m_mainFrame && m_webPage->m_mainFrame->view());
835
836     Frame* frame = m_webPage->focusedOrMainFrame();
837     WebCore::IntPoint clippedPoint = DOMSupport::convertPointToFrame(m_webPage->mainFrame(), frame, point, true /* clampToTargetFrame */);
838
839     if (m_webPage->m_inputHandler->isInputMode()
840             && frame->document()->focusedNode()
841             && frame->document()->focusedNode()->renderer()) {
842         WebCore::IntRect boundingBox(frame->document()->focusedNode()->renderer()->absoluteBoundingBoxRect());
843         boundingBox.inflate(-1);
844         clippedPoint = WebCore::IntPoint(clamp(boundingBox.x(), clippedPoint.x(), boundingBox.maxX()), clamp(boundingBox.y(), clippedPoint.y(), boundingBox.maxY()));
845     }
846
847     return clippedPoint;
848 }
849
850 static WebCore::IntPoint referencePoint(const VisiblePosition& position, const WebCore::IntRect& boundingRect, const WebCore::IntPoint& framePosition, bool isStartCaret, bool isRTL)
851 {
852     // If one of the carets is invalid (this happens, for instance, if the
853     // selection ends in an empty div) fall back to using the corner of the
854     // entire region (which is already in frame coordinates so doesn't need
855     // adjusting).
856     WebCore::IntRect startCaretBounds(position.absoluteCaretBounds());
857     startCaretBounds.move(framePosition.x(), framePosition.y());
858     if (startCaretBounds.isEmpty() || !boundingRect.contains(startCaretBounds))
859         startCaretBounds = boundingRect;
860
861     return caretComparisonPointForRect(startCaretBounds, isStartCaret, isRTL);
862 }
863
864 // Check all rects in the region for a point match. The region is non-banded
865 // and non-sorted so all must be checked.
866 static bool regionRectListContainsPoint(const IntRectRegion& region, const WebCore::IntPoint& point)
867 {
868     if (!region.extents().contains(point))
869         return false;
870
871     std::vector<Platform::IntRect> rectList = region.rects();
872     for (unsigned int i = 0; i < rectList.size(); i++) {
873         if (rectList[i].contains(point))
874             return true;
875     }
876     return false;
877 }
878
879 bool SelectionHandler::inputNodeOverridesTouch() const
880 {
881     if (!m_webPage->m_inputHandler->isInputMode())
882         return false;
883
884     Node* focusedNode = m_webPage->focusedOrMainFrame()->document()->focusedNode();
885     if (!focusedNode || !focusedNode->isElementNode())
886         return false;
887
888     // TODO consider caching this in InputHandler so it is only calculated once per focus.
889     DEFINE_STATIC_LOCAL(QualifiedName, selectionTouchOverrideAttr, (nullAtom, "data-blackberry-end-selection-on-touch", nullAtom));
890     Element* element = static_cast<Element*>(focusedNode);
891     return DOMSupport::elementAttributeState(element, selectionTouchOverrideAttr) == DOMSupport::On;
892 }
893
894 RequestedHandlePosition SelectionHandler::requestedSelectionHandlePosition(const VisibleSelection& selection) const
895 {
896     Element* element = DOMSupport::selectionContainerElement(selection);
897     return DOMSupport::elementHandlePositionAttribute(element);
898 }
899
900 // Note: This is the only function in SelectionHandler in which the coordinate
901 // system is not entirely WebKit.
902 void SelectionHandler::selectionPositionChanged(bool forceUpdateWithoutChange)
903 {
904     SelectionLog(Platform::LogLevelInfo,
905         "SelectionHandler::selectionPositionChanged forceUpdateWithoutChange = %s",
906         forceUpdateWithoutChange ? "true" : "false");
907
908     // This method can get called during WebPage shutdown process.
909     // If that is the case, just bail out since the client is not
910     // in a safe state of trust to request anything else from it.
911     if (!m_webPage->m_mainFrame)
912         return;
913
914     if (m_webPage->m_inputHandler->isInputMode() && m_webPage->m_inputHandler->processingChange()) {
915         if (m_webPage->m_selectionOverlay)
916             m_webPage->m_selectionOverlay->hide();
917         m_webPage->m_client->cancelSelectionVisuals();
918
919         // Since we're not calling notifyCaretPositionChangedIfNeeded now, we have to do so at the end of processing
920         // to avoid dropping a notification.
921         m_didSuppressCaretPositionChangedNotification = true;
922         return;
923     }
924
925     notifyCaretPositionChangedIfNeeded();
926
927     // Enter selection mode if selection type is RangeSelection, and disable selection if
928     // selection is active and becomes caret selection.
929     Frame* frame = m_webPage->focusedOrMainFrame();
930
931     if (frame->view()->needsLayout())
932         return;
933
934     WebCore::IntPoint framePos = m_webPage->frameOffset(frame);
935     if (m_selectionActive && (m_caretActive || frame->selection()->isNone()))
936         m_selectionActive = false;
937     else if (frame->selection()->isRange())
938         m_selectionActive = true;
939     else if (!m_selectionActive)
940         return;
941
942     SelectionTimingLog(Platform::LogLevelInfo,
943         "SelectionHandler::selectionPositionChanged starting at %f",
944         m_timer.elapsed());
945
946     WebCore::IntRect startCaret(DOMSupport::InvalidPoint, WebCore::IntSize());
947     WebCore::IntRect endCaret(DOMSupport::InvalidPoint, WebCore::IntSize());
948
949     // Get the text rects from the selections range.
950     Vector<FloatQuad> quads;
951     DOMSupport::visibleTextQuads(frame->selection()->selection(), quads);
952
953     IntRectRegion unclippedRegion;
954     regionForTextQuads(quads, unclippedRegion, false /* shouldClipToVisibleContent */);
955
956     // If there is no change in selected text and the visual rects
957     // have not changed then don't bother notifying anything.
958     if (!forceUpdateWithoutChange && m_lastSelectionRegion.isEqual(unclippedRegion))
959         return;
960
961     m_lastSelectionRegion = unclippedRegion;
962     bool isRTL = directionOfEnclosingBlock(frame->selection()) == RTL;
963
964     IntRectRegion visibleSelectionRegion;
965     if (!unclippedRegion.isEmpty()) {
966         WebCore::IntRect unclippedStartCaret;
967         WebCore::IntRect unclippedEndCaret;
968
969         WebCore::IntPoint startCaretReferencePoint = referencePoint(frame->selection()->selection().visibleStart(), unclippedRegion.extents(), framePos, true /* isStartCaret */, isRTL);
970         WebCore::IntPoint endCaretReferencePoint = referencePoint(frame->selection()->selection().visibleEnd(), unclippedRegion.extents(), framePos, false /* isStartCaret */, isRTL);
971
972         adjustCaretRects(unclippedStartCaret, false /* unclipped */, unclippedEndCaret, false /* unclipped */, unclippedRegion.rects(), startCaretReferencePoint, endCaretReferencePoint, isRTL);
973
974         regionForTextQuads(quads, visibleSelectionRegion);
975
976 #if SHOWDEBUG_SELECTIONHANDLER // Don't rely just on SelectionLog to avoid loop.
977         for (unsigned i = 0; i < unclippedRegion.numRects(); i++) {
978             SelectionLog(Platform::LogLevelInfo,
979                 "Rect list - Unmodified #%d, %s",
980                 i,
981                 unclippedRegion.rects()[i].toString().c_str());
982         }
983         for (unsigned i = 0; i < visibleSelectionRegion.numRects(); i++) {
984             SelectionLog(Platform::LogLevelInfo,
985                 "Rect list  - Clipped to Visible #%d, %s",
986                 i,
987                 visibleSelectionRegion.rects()[i].toString().c_str());
988         }
989 #endif
990
991         bool shouldCareAboutPossibleClippedOutSelection = frame != m_webPage->mainFrame() || m_webPage->m_inputHandler->isInputMode();
992
993         if (!visibleSelectionRegion.isEmpty() || shouldCareAboutPossibleClippedOutSelection) {
994             // Adjust the handle markers to be at the end of the painted rect. When selecting links
995             // and other elements that may have a larger visible area than needs to be rendered a gap
996             // can exist between the handle and overlay region.
997
998             bool shouldClipStartCaret = !regionRectListContainsPoint(visibleSelectionRegion, unclippedStartCaret.location());
999             bool shouldClipEndCaret = !regionRectListContainsPoint(visibleSelectionRegion, unclippedEndCaret.location());
1000
1001             // Find the top corner and bottom corner.
1002             adjustCaretRects(startCaret, shouldClipStartCaret, endCaret, shouldClipEndCaret, visibleSelectionRegion.rects(), startCaretReferencePoint, endCaretReferencePoint, isRTL);
1003         }
1004     }
1005
1006     if (!frame->selection()->selection().isBaseFirst() || isRTL ) {
1007         // End handle comes before start, invert the caret reference points.
1008         WebCore::IntRect tmpCaret(startCaret);
1009         startCaret = endCaret;
1010         endCaret = tmpCaret;
1011     }
1012
1013     SelectionLog(Platform::LogLevelInfo,
1014         "SelectionHandler::selectionPositionChanged Start Rect=%s End Rect=%s",
1015         Platform::IntRect(startCaret).toString().c_str(),
1016         Platform::IntRect(endCaret).toString().c_str());
1017
1018     if (m_webPage->m_selectionOverlay)
1019         m_webPage->m_selectionOverlay->draw(visibleSelectionRegion);
1020
1021
1022     VisibleSelection currentSelection = frame->selection()->selection();
1023     SelectionDetails details(startCaret, endCaret, visibleSelectionRegion, inputNodeOverridesTouch(),
1024         m_lastSelection != currentSelection, requestedSelectionHandlePosition(frame->selection()->selection()));
1025
1026     m_webPage->m_client->notifySelectionDetailsChanged(details);
1027     m_lastSelection = currentSelection;
1028     SelectionTimingLog(Platform::LogLevelInfo,
1029         "SelectionHandler::selectionPositionChanged completed at %f",
1030         m_timer.elapsed());
1031 }
1032
1033
1034 void SelectionHandler::notifyCaretPositionChangedIfNeeded(bool userTouchTriggered)
1035 {
1036     m_didSuppressCaretPositionChangedNotification = false;
1037
1038     if (m_caretActive || (m_webPage->m_inputHandler->isInputMode() && m_webPage->focusedOrMainFrame()->selection()->isCaret())) {
1039         // This may update the caret to no longer be active.
1040         caretPositionChanged(userTouchTriggered);
1041     }
1042 }
1043
1044 void SelectionHandler::caretPositionChanged(bool userTouchTriggered)
1045 {
1046     SelectionLog(Platform::LogLevelInfo, "SelectionHandler::caretPositionChanged");
1047
1048     bool isFatFingerOnTextField = userTouchTriggered && m_webPage->m_touchEventHandler->lastFatFingersResult().isTextInput();
1049
1050     WebCore::IntRect caretLocation;
1051     // If the input field is not active, we must be turning off the caret.
1052     if (!m_webPage->m_inputHandler->isInputMode() && m_caretActive) {
1053         m_caretActive = false;
1054         // Send an empty caret change to turn off the caret.
1055         m_webPage->m_client->notifyCaretChanged(caretLocation, isFatFingerOnTextField);
1056         return;
1057     }
1058
1059     ASSERT(m_webPage && m_webPage->focusedOrMainFrame() && m_webPage->focusedOrMainFrame()->selection());
1060
1061     // This function should only reach this point if input mode is active.
1062     ASSERT(m_webPage->m_inputHandler->isInputMode());
1063
1064     WebCore::IntPoint frameOffset(m_webPage->frameOffset(m_webPage->focusedOrMainFrame()));
1065     WebCore::IntRect clippingRectForContent(clippingRectForVisibleContent());
1066     if (m_webPage->focusedOrMainFrame()->selection()->selectionType() == VisibleSelection::CaretSelection) {
1067         caretLocation = m_webPage->focusedOrMainFrame()->selection()->selection().visibleStart().absoluteCaretBounds();
1068         caretLocation.move(frameOffset.x(), frameOffset.y());
1069
1070         // Clip against the containing frame and node boundaries.
1071         caretLocation.intersect(clippingRectForContent);
1072     }
1073
1074     m_caretActive = !caretLocation.isEmpty();
1075
1076     SelectionLog(Platform::LogLevelInfo,
1077         "SelectionHandler::caretPositionChanged caret Rect %s",
1078         Platform::IntRect(caretLocation).toString().c_str());
1079
1080     bool isSingleLineInput = !m_webPage->m_inputHandler->isMultilineInputMode();
1081     WebCore::IntRect nodeBoundingBox = isSingleLineInput ? m_webPage->m_inputHandler->boundingBoxForInputField() : WebCore::IntRect();
1082
1083     if (!nodeBoundingBox.isEmpty()) {
1084         nodeBoundingBox.move(frameOffset.x(), frameOffset.y());
1085
1086         // Clip against the containing frame and node boundaries.
1087         nodeBoundingBox.intersect(clippingRectForContent);
1088     }
1089
1090     SelectionLog(Platform::LogLevelInfo,
1091         "SelectionHandler::caretPositionChanged: %s line input, single line bounding box %s%s",
1092         isSingleLineInput ? "single" : "multi",
1093         Platform::IntRect(nodeBoundingBox).toString().c_str(),
1094         m_webPage->m_inputHandler->elementText().isEmpty() ? ", empty text field" : "");
1095
1096     m_webPage->m_client->notifyCaretChanged(caretLocation, isFatFingerOnTextField, isSingleLineInput, nodeBoundingBox, m_webPage->m_inputHandler->elementText().isEmpty());
1097 }
1098
1099 bool SelectionHandler::selectionContains(const WebCore::IntPoint& point)
1100 {
1101     ASSERT(m_webPage && m_webPage->focusedOrMainFrame() && m_webPage->focusedOrMainFrame()->selection());
1102     return m_webPage->focusedOrMainFrame()->selection()->contains(point);
1103 }
1104
1105 }
1106 }