FocusController::setFocusedNode() should be setFocusedElement().
[WebKit-https.git] / Source / WebKit / blackberry / WebKitSupport / SelectionHandler.cpp
index 7e2ade7..f5736f1 100644 (file)
 #include "Document.h"
 #include "FatFingers.h"
 #include "FloatQuad.h"
+#include "FocusController.h"
 #include "Frame.h"
 #include "FrameSelection.h"
 #include "FrameView.h"
 #include "HitTestResult.h"
 #include "InputHandler.h"
 #include "IntRect.h"
+#include "Page.h"
 #include "RenderLayer.h"
 #include "SelectionOverlay.h"
 #include "TouchEventHandler.h"
+#include "VisibleUnits.h"
 #include "WebPageClient.h"
 #include "WebPage_p.h"
 
 #include "htmlediting.h"
-#include "visible_units.h"
 
 #include <BlackBerryPlatformKeyboardEvent.h>
 #include <BlackBerryPlatformLog.h>
@@ -91,6 +93,8 @@ void SelectionHandler::cancelSelection()
     // rendering happened prior to processing on webkit thread
     m_webPage->m_client->notifySelectionDetailsChanged(SelectionDetails());
 
+    m_webPage->updateSelectionScrollView(0);
+
     SelectionLog(Platform::LogLevelInfo, "SelectionHandler::cancelSelection");
 
     if (m_webPage->m_inputHandler->isInputMode())
@@ -101,7 +105,7 @@ void SelectionHandler::cancelSelection()
 
 BlackBerry::Platform::String SelectionHandler::selectedText() const
 {
-    return m_webPage->focusedOrMainFrame()->editor()->selectedText();
+    return m_webPage->focusedOrMainFrame()->editor().selectedText();
 }
 
 WebCore::IntRect SelectionHandler::clippingRectForVisibleContent() const
@@ -154,7 +158,7 @@ void SelectionHandler::regionForTextQuads(Vector<FloatQuad> &quadList, IntRectRe
                 enclosingRect.intersect(clippingRect);
 
             adjustedIntRects.push_back(enclosingRect);
-            selectionBoundingBox = unionOfRects(enclosingRect, selectionBoundingBox);
+            selectionBoundingBox.unite(enclosingRect);
         }
         region = IntRectRegion(selectionBoundingBox, adjustedIntRects.size(), adjustedIntRects);
     }
@@ -168,7 +172,7 @@ static VisiblePosition visiblePositionForPointIgnoringClipping(const Frame& fram
     // outside the visible rect. To work around the bug, this is a copy of
     // visiblePositionAtPoint which which passes ignoreClipping=true.
     // See RIM Bug #4315.
-    HitTestResult result = frame.eventHandler()->hitTestResultAtPoint(framePoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::AllowShadowContent | HitTestRequest::IgnoreClipping);
+    HitTestResult result = frame.eventHandler()->hitTestResultAtPoint(framePoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping);
 
     Node* node = result.innerNode();
     if (!node || node->document() != frame.document())
@@ -313,7 +317,7 @@ static bool shouldExtendSelectionInDirection(const VisibleSelection& selection,
 
     if ((character == KEYCODE_LEFT || character == KEYCODE_RIGHT)
         && (!inSameLine(selection.visibleStart(), tempSelection.selection().visibleStart())
-           || !inSameLine(selection.visibleEnd(), tempSelection.selection().visibleEnd())))
+            || !inSameLine(selection.visibleEnd(), tempSelection.selection().visibleEnd())))
         return false;
 
     return tempSelection.selection().selectionType() == VisibleSelection::RangeSelection;
@@ -368,10 +372,9 @@ unsigned SelectionHandler::extendSelectionToFieldBoundary(bool isStartHandle, co
     if (!focusedFrame->document()->focusedNode() || !focusedFrame->document()->focusedNode()->renderer())
         return 0;
 
-    FrameSelection* controller = focusedFrame->selection();
+    VisibleSelection activeSelection = focusedFrame->selection()->selection();
 
-    WebCore::IntRect caretRect = isStartHandle ? controller->selection().visibleStart().absoluteCaretBounds()
-                                      : controller->selection().visibleEnd().absoluteCaretBounds();
+    WebCore::IntRect caretRect = isStartHandle ? activeSelection.visibleStart().absoluteCaretBounds() : activeSelection.visibleEnd().absoluteCaretBounds();
 
     WebCore::IntRect nodeBoundingBox = focusedFrame->document()->focusedNode()->renderer()->absoluteBoundingBoxRect();
     nodeBoundingBox.inflate(-1);
@@ -382,11 +385,11 @@ unsigned SelectionHandler::extendSelectionToFieldBoundary(bool isStartHandle, co
 
     // Prevent incorrect movement, handles can only extend the selection this way
     // to prevent inversion of the handles.
-    if (isStartHandle && (character == KEYCODE_RIGHT || character == KEYCODE_DOWN)
-        || !isStartHandle && (character == KEYCODE_LEFT || character == KEYCODE_UP))
+    if ((isStartHandle && (character == KEYCODE_RIGHT || character == KEYCODE_DOWN))
+        || (!isStartHandle && (character == KEYCODE_LEFT || character == KEYCODE_UP)))
         character = 0;
 
-    VisiblePosition newVisiblePosition = isStartHandle ? controller->selection().extent() : controller->selection().base();
+    VisiblePosition newVisiblePosition = isStartHandle ? activeSelection.extent() : activeSelection.base();
     // Extend the selection to the bounds of the box before doing incremental scroll if the point is outside the node.
     // Don't extend selection and handle the character at the same time.
     if (pointIsOutsideOfBoundingBoxInDirection(character, selectionPoint, nodeBoundingBox))
@@ -398,7 +401,7 @@ unsigned SelectionHandler::extendSelectionToFieldBoundary(bool isStartHandle, co
         newSelection = VisibleSelection(newSelection.base(), newVisiblePosition, true /* isDirectional */);
 
     // If no selection will be changed, return the character to extend using navigation.
-    if (controller->selection() == newSelection)
+    if (activeSelection == newSelection)
         return character;
 
     // Selection has been updated.
@@ -406,8 +409,7 @@ unsigned SelectionHandler::extendSelectionToFieldBoundary(bool isStartHandle, co
 }
 
 // Returns true if handled.
-bool SelectionHandler::updateOrHandleInputSelection(VisibleSelection& newSelection, const WebCore::IntPoint& relativeStart
-                                                    , const WebCore::IntPoint& relativeEnd)
+bool SelectionHandler::updateOrHandleInputSelection(VisibleSelection& newSelection, const WebCore::IntPoint& relativeStart, const WebCore::IntPoint& relativeEnd)
 {
     ASSERT(m_webPage->m_inputHandler->isInputMode());
 
@@ -472,7 +474,7 @@ bool SelectionHandler::updateOrHandleInputSelection(VisibleSelection& newSelecti
     return true;
 }
 
-void SelectionHandler::setSelection(const WebCore::IntPoint& start, const WebCore::IntPoint& end)
+void SelectionHandler::setSelection(WebCore::IntPoint start, WebCore::IntPoint end)
 {
     m_selectionActive = true;
 
@@ -500,43 +502,45 @@ void SelectionHandler::setSelection(const WebCore::IntPoint& start, const WebCor
     // At least one of the locations must be valid.
     ASSERT(startIsValid || m_lastUpdatedEndPointIsValid);
 
+    if (m_webPage->m_inputHandler->isInputMode() && !m_webPage->m_inputHandler->isMultilineInputMode()) {
+        WebCore::IntRect caret(startCaretViewportRect(m_webPage->frameOffset(focusedFrame)));
+        if (!caret.isEmpty()) {
+            int centerOfCaretY = caret.center().y();
+            if (startIsValid)
+                start.setY(centerOfCaretY);
+            if (m_lastUpdatedEndPointIsValid)
+                end.setY(centerOfCaretY);
+        }
+    }
+
     WebCore::IntPoint relativeStart = start;
     WebCore::IntPoint relativeEnd = end;
 
-    VisibleSelection newSelection(controller->selection());
-
-    // We need the selection to be ordered base then extent.
-    if (!controller->selection().isBaseFirst())
-        controller->setSelection(VisibleSelection(controller->selection().start(), controller->selection().end(), true /* isDirectional */));
+    // Initialize the new start and end of our selection at the current positions.
+    VisiblePosition newStart = controller->selection().visibleStart();
+    VisiblePosition newEnd = controller->selection().visibleEnd();
 
     // We don't return early in the following, so that we can do input field scrolling if the
     // handle is outside the bounds of the field. This can be extended to handle sub-region
     // scrolling as well
     if (startIsValid) {
         relativeStart = DOMSupport::convertPointToFrame(m_webPage->mainFrame(), focusedFrame, start);
-
         VisiblePosition base = visiblePositionForPointIgnoringClipping(*focusedFrame, clipPointToVisibleContainer(start));
-        if (base.isNotNull()) {
-            // The function setBase validates the "base"
-            newSelection.setBase(base);
-            newSelection.setWithoutValidation(newSelection.base(), controller->selection().end());
-            // Don't return early.
-        }
+        if (base.isNotNull())
+            newStart = base;
     }
 
     if (m_lastUpdatedEndPointIsValid) {
         relativeEnd = DOMSupport::convertPointToFrame(m_webPage->mainFrame(), focusedFrame, end);
-
         VisiblePosition extent = visiblePositionForPointIgnoringClipping(*focusedFrame, clipPointToVisibleContainer(end));
-        if (extent.isNotNull()) {
-            // The function setExtent validates the "extent"
-            newSelection.setExtent(extent);
-            newSelection.setWithoutValidation(controller->selection().start(), newSelection.extent());
-            // Don't return early.
-        }
+        if (extent.isNotNull())
+            newEnd = extent;
     }
 
-    newSelection.setIsDirectional(true);
+    VisibleSelection newSelection(newStart, newEnd, true /* isDirectional */);
+
+    if (!controller->selection().isRange())
+        m_webPage->updateSelectionScrollView(newSelection.visibleEnd().deepEquivalent().anchorNode());
 
     if (m_webPage->m_inputHandler->isInputMode()) {
         if (updateOrHandleInputSelection(newSelection, relativeStart, relativeEnd))
@@ -628,6 +632,21 @@ bool SelectionHandler::selectNodeIfFatFingersResultIsLink(FatFingersResult fatFi
     return false;
 }
 
+WebCore::IntRect SelectionHandler::startCaretViewportRect(const WebCore::IntPoint& frameOffset) const
+{
+    WebCore::IntRect caretRect;
+    Frame* frame = m_webPage->focusedOrMainFrame();
+    if (!frame)
+        return caretRect;
+
+    if (frame->selection()->selectionType() != VisibleSelection::NoSelection) {
+        caretRect = frame->selection()->selection().visibleStart().absoluteCaretBounds();
+        caretRect.moveBy(frameOffset);
+    }
+
+    return caretRect;
+}
+
 void SelectionHandler::selectAtPoint(const WebCore::IntPoint& location, SelectionExpansionType selectionExpansionType)
 {
     if (selectionExpansionType == Word) {
@@ -635,6 +654,7 @@ void SelectionHandler::selectAtPoint(const WebCore::IntPoint& location, Selectio
         m_animationOverlayEndPos = VisiblePosition();
         m_currentAnimationOverlayRegion = IntRectRegion();
         m_nextAnimationOverlayRegion = IntRectRegion();
+        m_selectionSubframeViewportRect = WebCore::IntRect();
     }
 
     // If point is invalid trigger selection based expansion.
@@ -648,7 +668,7 @@ void SelectionHandler::selectAtPoint(const WebCore::IntPoint& location, Selectio
     FatFingersResult fatFingersResult = m_webPage->m_touchEventHandler->lastFatFingersResult();
     if (selectNodeIfFatFingersResultIsLink(fatFingersResult))
         return;
-    if (!fatFingersResult.resultMatches(location, FatFingers::Text) || !fatFingersResult.positionWasAdjusted() || !fatFingersResult.nodeAsElem
+    if (!fatFingersResult.resultMatches(location, FatFingers::Text) || !fatFingersResult.positionWasAdjusted() || !fatFingersResult.nodeAsElementIfApplicable())
         fatFingersResult = FatFingers(m_webPage, location, FatFingers::Text).findBestPoint();
 
     if (!fatFingersResult.positionWasAdjusted()) {
@@ -666,11 +686,6 @@ void SelectionHandler::selectAtPoint(const WebCore::IntPoint& location, Selectio
     selectObject(targetPosition, textGranularityFromSelectionExpansionType(selectionExpansionType));
 }
 
-static bool isInvalidLine(const VisiblePosition& pos)
-{
-    return endOfLine(pos).isNull() || pos == endOfLine(pos) || !inSameLine(pos, endOfLine(pos));
-}
-
 static bool isInvalidParagraph(const VisiblePosition& pos)
 {
     return endOfParagraph(pos).isNull() || pos == endOfParagraph(pos);
@@ -681,14 +696,14 @@ void SelectionHandler::selectNextParagraph()
     FrameSelection* controller = m_webPage->focusedOrMainFrame()->selection();
 
     VisiblePosition startPos = VisiblePosition(controller->start(), controller->affinity());
-    if (isStartOfLine(startPos) && isEndOfEditableOrNonEditableContent(startPos))
-        startPos = startPos.previous();
+    if (isStartOfLine(startPos) && isEndOfDocument(startPos))
+        startPos = startPos.previous(CannotCrossEditingBoundary);
 
     // Find next paragraph end position.
     VisiblePosition endPos(controller->end(), controller->affinity()); // endPos here indicates the end of current paragraph
-    endPos = endPos.next(); // find the start of next paragraph
-    while (!isEndOfDocument(endPos.deepEquivalent()) && endPos.isNotNull() && isInvalidParagraph(endPos))
-        endPos = endPos.next(); // go to next position
+    endPos = endPos.next(CannotCrossEditingBoundary); // find the start of next paragraph
+    while (!isEndOfDocument(endPos) && endPos.isNotNull() && isInvalidParagraph(endPos))
+        endPos = endPos.next(CannotCrossEditingBoundary); // go to next position
     endPos = endOfParagraph(endPos); // find the end of paragraph
 
     // Set selection if the paragraph is covered by overlay and endPos is not null.
@@ -698,7 +713,7 @@ void SelectionHandler::selectNextParagraph()
         controller->setSelection(selection);
 
         // Stop expansion if reaching the end of page.
-        if (isEndOfDocument(endPos.deepEquivalent()))
+        if (isEndOfDocument(endPos))
             m_webPage->m_client->stopExpandingSelection();
     }
 }
@@ -733,13 +748,13 @@ IntRectRegion SelectionHandler::regionForSelectionQuads(VisibleSelection selecti
 bool SelectionHandler::findNextAnimationOverlayRegion()
 {
     // If overlay is at the end of document, stop overlay expansion.
-    if (isEndOfDocument(m_animationOverlayEndPos.deepEquivalent()) || m_animationOverlayEndPos.isNull())
+    if (isEndOfDocument(m_animationOverlayEndPos) || m_animationOverlayEndPos.isNull())
         return false;
 
-    m_animationOverlayEndPos = m_animationOverlayEndPos.next();
-    while (!isEndOfDocument(m_animationOverlayEndPos.deepEquivalent()) && m_animationOverlayEndPos.isNotNull() && isInvalidLine(m_animationOverlayEndPos))
-        m_animationOverlayEndPos = m_animationOverlayEndPos.next(); // go to next position
-    m_animationOverlayEndPos = endOfLine(m_animationOverlayEndPos); // find end of line
+    m_animationOverlayEndPos = m_animationOverlayEndPos.next(CannotCrossEditingBoundary);
+    while (!isEndOfDocument(m_animationOverlayEndPos) && m_animationOverlayEndPos.isNotNull() && isInvalidParagraph(m_animationOverlayEndPos))
+        m_animationOverlayEndPos = m_animationOverlayEndPos.next(CannotCrossEditingBoundary); // go to next position
+    m_animationOverlayEndPos = endOfParagraph(m_animationOverlayEndPos); // find end of paragraph
 
     VisibleSelection selection(m_animationOverlayStartPos, m_animationOverlayEndPos);
     m_nextAnimationOverlayRegion = regionForSelectionQuads(selection);
@@ -756,7 +771,6 @@ void SelectionHandler::expandSelection(bool isScrollStarted)
         if (!findNextAnimationOverlayRegion()) {
             drawAnimationOverlay(m_nextAnimationOverlayRegion, false);
             selectNextParagraph();
-            m_webPage->m_client->stopExpandingSelection();
             return;
         }
 
@@ -774,12 +788,14 @@ void SelectionHandler::expandSelection(bool isScrollStarted)
 
 bool SelectionHandler::ensureSelectedTextVisible(const WebCore::IntPoint& point, bool scrollIfNeeded)
 {
-    WebCore::IntPoint scrollPosition = m_webPage->scrollPosition();
-    WebCore::IntSize actualVisibleSize = m_webPage->client()->userInterfaceViewportAccessor()->documentViewportRect().size(); // viewport size for both Cascades and browser
-    WebCore::IntRect actualScreenRect = WebCore::IntRect(scrollPosition, actualVisibleSize);
-
+    WebCore::IntRect viewportRect = selectionViewportRect();
     if (!scrollIfNeeded)
-        return actualScreenRect.maxY() >= point.y() + m_scrollMargin.height();
+        // If reaching the bottom of content, ignore scroll margin so the text on the bottom can be selected.
+        return viewportRect.maxY() >= m_webPage->contentsSize().height() ? viewportRect.maxY() >= point.y() : viewportRect.maxY() >= point.y() + m_scrollMargin.height();
+
+    // Scroll position adjustment here is based on main frame. If selecting in a subframe, don't do animation.
+    if (!m_selectionSubframeViewportRect.isEmpty())
+        return false;
 
     WebCore::IntRect endLocation = m_animationOverlayEndPos.absoluteCaretBounds();
 
@@ -800,7 +816,7 @@ bool SelectionHandler::ensureSelectedTextVisible(const WebCore::IntPoint& point,
     endLocation.inflateX(m_scrollMargin.width());
     endLocation.inflateY(m_scrollMargin.height());
 
-    WebCore::IntRect revealRect(layer->getRectToExpose(actualScreenRect, endLocation, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded));
+    WebCore::IntRect revealRect(layer->getRectToExpose(viewportRect, endLocation, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded));
     revealRect.setX(std::min(std::max(revealRect.x(), 0), m_webPage->maximumScrollPosition().x()));
     revealRect.setY(std::min(std::max(revealRect.y(), 0), m_webPage->maximumScrollPosition().y()));
 
@@ -809,6 +825,13 @@ bool SelectionHandler::ensureSelectedTextVisible(const WebCore::IntPoint& point,
     return true;
 }
 
+WebCore::IntRect SelectionHandler::selectionViewportRect() const
+{
+    if (m_selectionSubframeViewportRect.isEmpty())
+        return WebCore::IntRect(m_webPage->scrollPosition(), m_selectionViewportSize);
+    return m_selectionSubframeViewportRect;
+}
+
 void SelectionHandler::setParagraphExpansionScrollMargin(const WebCore::IntSize& scrollMargin)
 {
     m_scrollMargin.setWidth(scrollMargin.width());
@@ -836,6 +859,8 @@ bool SelectionHandler::expandSelectionToGranularity(Frame* frame, VisibleSelecti
     m_animationOverlayEndPos = selection.visibleEnd();
 
     if (granularity == WordGranularity) {
+        m_webPage->updateSelectionScrollView(selection.visibleEnd().deepEquivalent().anchorNode());
+
         Element* element = m_animationOverlayStartPos.deepEquivalent().element();
         if (!element)
             return false;
@@ -847,7 +872,6 @@ bool SelectionHandler::expandSelectionToGranularity(Frame* frame, VisibleSelecti
     frame->selection()->setSelection(selection);
     if (granularity == ParagraphGranularity)
         findNextAnimationOverlayRegion();
-
     return true;
 }
 
@@ -862,13 +886,17 @@ void SelectionHandler::selectObject(const WebCore::IntPoint& location, TextGranu
         Platform::IntPoint(location).toString().c_str());
 
     WebCore::IntPoint relativePoint = DOMSupport::convertPointToFrame(m_webPage->mainFrame(), focusedFrame, location);
-    // Clear input focus if we're not selecting in old input field.
-    if (!m_webPage->m_inputHandler->boundingBoxForInputField().contains(relativePoint))
-        m_webPage->clearFocusNode();
 
     VisiblePosition pointLocation(focusedFrame->visiblePositionForPoint(relativePoint));
     VisibleSelection selection = VisibleSelection(pointLocation, pointLocation);
 
+    // Move focus to the new node if we're not selecting in old input field.
+    if (!m_webPage->m_inputHandler->boundingBoxForInputField().contains(relativePoint)) {
+        Node* anchorNode = selection.start().anchorNode();
+        if (!anchorNode || anchorNode->isElementNode())
+            m_webPage->m_page->focusController()->setFocusedElement(toElement(anchorNode), focusedFrame);
+    }
+
     m_selectionActive = expandSelectionToGranularity(focusedFrame, selection, granularity, m_webPage->m_inputHandler->isInputMode());
 }
 
@@ -915,6 +943,7 @@ void SelectionHandler::selectObject(Node* node)
     VisibleSelection selection = VisibleSelection::selectionFromContentsOfNode(node);
     drawAnimationOverlay(regionForSelectionQuads(selection), false /* isExpandingOverlayAtConstantRate */, true /* isStartOfSelection */);
     focusedFrame->selection()->setSelection(selection);
+    m_webPage->updateSelectionScrollView(node);
 }
 
 static TextDirection directionOfEnclosingBlock(FrameSelection* selection)
@@ -980,12 +1009,8 @@ static inline WebCore::IntPoint caretComparisonPointForRect(const WebCore::IntRe
     return caretIsOnLeft(isStartCaret, isRTL) ? minXMaxYCorner(rect) : maxXMaxYCorner(rect);
 }
 
-static void adjustCaretRects(WebCore::IntRect& startCaret, bool isStartCaretClippedOut,
-                             WebCore::IntRect& endCaret, bool isEndCaretClippedOut,
-                             const std::vector<Platform::IntRect> rectList,
-                             const WebCore::IntPoint& startReferencePoint,
-                             const WebCore::IntPoint& endReferencePoint,
-                             bool isRTL)
+static void adjustCaretRects(WebCore::IntRect& startCaret, bool isStartCaretClippedOut, WebCore::IntRect& endCaret, bool isEndCaretClippedOut,
+    const std::vector<Platform::IntRect> rectList, const WebCore::IntPoint& startReferencePoint, const WebCore::IntPoint& endReferencePoint, bool isRTL)
 {
     // startReferencePoint is the best guess at the top left of the selection; endReferencePoint is the best guess at the bottom right.
     if (isStartCaretClippedOut)
@@ -1014,19 +1039,19 @@ static void adjustCaretRects(WebCore::IntRect& startCaret, bool isStartCaretClip
 
         // Compare and update the start and end carets with their respective reference points.
         if (!isStartCaretClippedOut && comparePointsToReferencePoint(
-                    caretComparisonPointForRect(currentRect, true, isRTL),
-                    caretComparisonPointForRect(startCaret, true, isRTL),
-                    startReferencePoint, isRTL) > 0) {
-            startCaret.setLocation(caretLocationForRect(currentRect, true, isRTL));
-            startCaret.setHeight(currentRect.height());
+            caretComparisonPointForRect(currentRect, true, isRTL),
+            caretComparisonPointForRect(startCaret, true, isRTL),
+            startReferencePoint, isRTL) > 0) {
+                startCaret.setLocation(caretLocationForRect(currentRect, true, isRTL));
+                startCaret.setHeight(currentRect.height());
         }
 
         if (!isEndCaretClippedOut && comparePointsToReferencePoint(
-                    caretComparisonPointForRect(currentRect, false, isRTL),
-                    caretComparisonPointForRect(endCaret, false, isRTL),
-                    endReferencePoint, !isRTL) > 0) {
-            endCaret.setLocation(caretLocationForRect(currentRect, false, isRTL));
-            endCaret.setHeight(currentRect.height());
+            caretComparisonPointForRect(currentRect, false, isRTL),
+            caretComparisonPointForRect(endCaret, false, isRTL),
+            endReferencePoint, !isRTL) > 0) {
+                endCaret.setLocation(caretLocationForRect(currentRect, false, isRTL));
+                endCaret.setHeight(currentRect.height());
         }
     }
 }
@@ -1039,11 +1064,11 @@ WebCore::IntPoint SelectionHandler::clipPointToVisibleContainer(const WebCore::I
     WebCore::IntPoint clippedPoint = DOMSupport::convertPointToFrame(m_webPage->mainFrame(), frame, point, true /* clampToTargetFrame */);
 
     if (m_webPage->m_inputHandler->isInputMode()
-            && frame->document()->focusedNode()
-            && frame->document()->focusedNode()->renderer()) {
-        WebCore::IntRect boundingBox(frame->document()->focusedNode()->renderer()->absoluteBoundingBoxRect());
-        boundingBox.inflate(-1);
-        clippedPoint = WebCore::IntPoint(clamp(boundingBox.x(), clippedPoint.x(), boundingBox.maxX()), clamp(boundingBox.y(), clippedPoint.y(), boundingBox.maxY()));
+        && frame->document()->focusedNode()
+        && frame->document()->focusedNode()->renderer()) {
+            WebCore::IntRect boundingBox(frame->document()->focusedNode()->renderer()->absoluteBoundingBoxRect());
+            boundingBox.inflate(-1);
+            clippedPoint = WebCore::IntPoint(clamp(boundingBox.x(), clippedPoint.x(), boundingBox.maxX()), clamp(boundingBox.y(), clippedPoint.y(), boundingBox.maxY()));
     }
 
     return clippedPoint;
@@ -1071,7 +1096,7 @@ static bool regionRectListContainsPoint(const IntRectRegion& region, const WebCo
         return false;
 
     std::vector<Platform::IntRect> rectList = region.rects();
-    for (unsigned int i = 0; i < rectList.size(); i++) {
+    for (unsigned i = 0; i < rectList.size(); i++) {
         if (rectList[i].contains(point))
             return true;
     }
@@ -1089,7 +1114,7 @@ bool SelectionHandler::inputNodeOverridesTouch() const
 
     // TODO consider caching this in InputHandler so it is only calculated once per focus.
     DEFINE_STATIC_LOCAL(QualifiedName, selectionTouchOverrideAttr, (nullAtom, "data-blackberry-end-selection-on-touch", nullAtom));
-    Element* element = static_cast<Element*>(focusedNode);
+    Element* element = toElement(focusedNode);
     return DOMSupport::elementAttributeState(element, selectionTouchOverrideAttr) == DOMSupport::On;
 }
 
@@ -1124,7 +1149,7 @@ void SelectionHandler::selectionPositionChanged(bool forceUpdateWithoutChange)
         return;
     }
 
-    notifyCaretPositionChangedIfNeeded();
+    notifyCaretPositionChangedIfNeeded(m_webPage->m_touchEventHandler->m_userTriggeredTouchPressOnTextInput);
 
     // Enter selection mode if selection type is RangeSelection, and disable selection if
     // selection is active and becomes caret selection.
@@ -1141,6 +1166,13 @@ void SelectionHandler::selectionPositionChanged(bool forceUpdateWithoutChange)
     else if (!m_selectionActive)
         return;
 
+    if (Node* focusedNode = frame->document()->focusedNode()) {
+        if (focusedNode->hasTagName(HTMLNames::selectTag) || (focusedNode->isElementNode() && DOMSupport::isPopupInputField(toElement(focusedNode)))) {
+            SelectionLog(Platform::LogLevelInfo, "SelectionHandler::selectionPositionChanged selection is on a popup control, skipping rendering.");
+            return;
+        }
+    }
+
     SelectionTimingLog(Platform::LogLevelInfo,
         "SelectionHandler::selectionPositionChanged starting at %f",
         m_timer.elapsed());
@@ -1205,7 +1237,7 @@ void SelectionHandler::selectionPositionChanged(bool forceUpdateWithoutChange)
         }
     }
 
-    if (!frame->selection()->selection().isBaseFirst() || isRTL ) {
+    if (!frame->selection()->selection().isBaseFirst()) {
         // End handle comes before start, invert the caret reference points.
         WebCore::IntRect tmpCaret(startCaret);
         startCaret = endCaret;
@@ -1220,10 +1252,9 @@ void SelectionHandler::selectionPositionChanged(bool forceUpdateWithoutChange)
     if (m_webPage->m_selectionOverlay)
         m_webPage->m_selectionOverlay->draw(visibleSelectionRegion);
 
-
     VisibleSelection currentSelection = frame->selection()->selection();
     SelectionDetails details(startCaret, endCaret, visibleSelectionRegion, inputNodeOverridesTouch(),
-        m_lastSelection != currentSelection, requestedSelectionHandlePosition(frame->selection()->selection()));
+        m_lastSelection != currentSelection, requestedSelectionHandlePosition(frame->selection()->selection()), isRTL);
 
     m_webPage->m_client->notifySelectionDetailsChanged(details);
     m_lastSelection = currentSelection;
@@ -1233,28 +1264,26 @@ void SelectionHandler::selectionPositionChanged(bool forceUpdateWithoutChange)
 }
 
 
-void SelectionHandler::notifyCaretPositionChangedIfNeeded(bool userTouchTriggered)
+void SelectionHandler::notifyCaretPositionChangedIfNeeded(bool userTouchTriggeredOnTextField)
 {
     m_didSuppressCaretPositionChangedNotification = false;
 
     if (m_caretActive || (m_webPage->m_inputHandler->isInputMode() && m_webPage->focusedOrMainFrame()->selection()->isCaret())) {
         // This may update the caret to no longer be active.
-        caretPositionChanged(userTouchTriggered);
+        caretPositionChanged(userTouchTriggeredOnTextField);
     }
 }
 
-void SelectionHandler::caretPositionChanged(bool userTouchTriggered)
+void SelectionHandler::caretPositionChanged(bool userTouchTriggeredOnTextField)
 {
     SelectionLog(Platform::LogLevelInfo, "SelectionHandler::caretPositionChanged");
 
-    bool isFatFingerOnTextField = userTouchTriggered && m_webPage->m_touchEventHandler->lastFatFingersResult().isTextInput();
-
     WebCore::IntRect caretLocation;
     // If the input field is not active, we must be turning off the caret.
     if (!m_webPage->m_inputHandler->isInputMode() && m_caretActive) {
         m_caretActive = false;
         // Send an empty caret change to turn off the caret.
-        m_webPage->m_client->notifyCaretChanged(caretLocation, isFatFingerOnTextField);
+        m_webPage->m_client->notifyCaretChanged(caretLocation, userTouchTriggeredOnTextField);
         return;
     }
 
@@ -1263,14 +1292,12 @@ void SelectionHandler::caretPositionChanged(bool userTouchTriggered)
     // This function should only reach this point if input mode is active.
     ASSERT(m_webPage->m_inputHandler->isInputMode());
 
-    WebCore::IntPoint frameOffset(m_webPage->frameOffset(m_webPage->focusedOrMainFrame()));
     WebCore::IntRect clippingRectForContent(clippingRectForVisibleContent());
+    WebCore::IntPoint frameOffset(m_webPage->frameOffset(m_webPage->focusedOrMainFrame()));
     if (m_webPage->focusedOrMainFrame()->selection()->selectionType() == VisibleSelection::CaretSelection) {
-        caretLocation = m_webPage->focusedOrMainFrame()->selection()->selection().visibleStart().absoluteCaretBounds();
-        caretLocation.move(frameOffset.x(), frameOffset.y());
-
-        // Clip against the containing frame and node boundaries.
-        caretLocation.intersect(clippingRectForContent);
+        caretLocation = startCaretViewportRect(frameOffset);
+        if (!caretLocation.isEmpty())
+            caretLocation.intersect(clippingRectForContent); // Clip against the containing frame and node boundaries.
     }
 
     m_caretActive = !caretLocation.isEmpty();
@@ -1279,11 +1306,11 @@ void SelectionHandler::caretPositionChanged(bool userTouchTriggered)
         "SelectionHandler::caretPositionChanged caret Rect %s",
         Platform::IntRect(caretLocation).toString().c_str());
 
-    bool isSingleLineInput = !m_webPage->m_inputHandler->isMultilineInputMode();
+    bool isSingleLineInput = m_caretActive && !m_webPage->m_inputHandler->isMultilineInputMode();
     WebCore::IntRect nodeBoundingBox = isSingleLineInput ? m_webPage->m_inputHandler->boundingBoxForInputField() : WebCore::IntRect();
 
     if (!nodeBoundingBox.isEmpty()) {
-        nodeBoundingBox.move(frameOffset.x(), frameOffset.y());
+        nodeBoundingBox.moveBy(frameOffset);
 
         // Clip against the containing frame and node boundaries.
         nodeBoundingBox.intersect(clippingRectForContent);
@@ -1295,7 +1322,7 @@ void SelectionHandler::caretPositionChanged(bool userTouchTriggered)
         Platform::IntRect(nodeBoundingBox).toString().c_str(),
         m_webPage->m_inputHandler->elementText().isEmpty() ? ", empty text field" : "");
 
-    m_webPage->m_client->notifyCaretChanged(caretLocation, isFatFingerOnTextField, isSingleLineInput, nodeBoundingBox, m_webPage->m_inputHandler->elementText().isEmpty());
+    m_webPage->m_client->notifyCaretChanged(caretLocation, userTouchTriggeredOnTextField, isSingleLineInput, nodeBoundingBox, m_webPage->m_inputHandler->elementText().isEmpty());
 }
 
 bool SelectionHandler::selectionContains(const WebCore::IntPoint& point)