Home | History | Annotate | Download | only in editing
      1 /*
      2  * Copyright (C) 2004, 2008, 2009, 2010 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "SelectionController.h"
     28 
     29 #include "CharacterData.h"
     30 #include "DeleteSelectionCommand.h"
     31 #include "Document.h"
     32 #include "Editor.h"
     33 #include "EditorClient.h"
     34 #include "Element.h"
     35 #include "EventHandler.h"
     36 #include "ExceptionCode.h"
     37 #include "FloatQuad.h"
     38 #include "FocusController.h"
     39 #include "Frame.h"
     40 #include "FrameTree.h"
     41 #include "FrameView.h"
     42 #include "GraphicsContext.h"
     43 #include "HTMLFormElement.h"
     44 #include "HTMLFrameElementBase.h"
     45 #include "HTMLInputElement.h"
     46 #include "HTMLNames.h"
     47 #include "HitTestRequest.h"
     48 #include "HitTestResult.h"
     49 #include "Page.h"
     50 #include "Range.h"
     51 #include "RenderLayer.h"
     52 #include "RenderTextControl.h"
     53 #include "RenderTheme.h"
     54 #include "RenderView.h"
     55 #include "RenderWidget.h"
     56 #include "SecureTextInput.h"
     57 #include "Settings.h"
     58 #include "TextIterator.h"
     59 #include "TypingCommand.h"
     60 #include "htmlediting.h"
     61 #include "visible_units.h"
     62 #ifdef ANDROID_ALLOW_TURNING_OFF_CARET
     63 #include "WebViewCore.h"
     64 #endif
     65 #include <stdio.h>
     66 #include <wtf/text/CString.h>
     67 
     68 #define EDIT_DEBUG 0
     69 
     70 namespace WebCore {
     71 
     72 using namespace HTMLNames;
     73 
     74 const int NoXPosForVerticalArrowNavigation = INT_MIN;
     75 
     76 SelectionController::SelectionController(Frame* frame, bool isDragCaretController)
     77     : m_frame(frame)
     78     , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation)
     79     , m_granularity(CharacterGranularity)
     80     , m_caretBlinkTimer(this, &SelectionController::caretBlinkTimerFired)
     81     , m_caretRectNeedsUpdate(true)
     82     , m_absCaretBoundsDirty(true)
     83     , m_isDragCaretController(isDragCaretController)
     84     , m_isCaretBlinkingSuspended(false)
     85     , m_focused(frame && frame->page() && frame->page()->focusController()->focusedFrame() == frame)
     86     , m_caretVisible(isDragCaretController)
     87     , m_caretPaint(true)
     88 {
     89     setIsDirectional(false);
     90 }
     91 
     92 void SelectionController::moveTo(const VisiblePosition &pos, bool userTriggered, CursorAlignOnScroll align)
     93 {
     94     SetSelectionOptions options = CloseTyping | ClearTypingStyle;
     95     if (userTriggered)
     96         options |= UserTriggered;
     97     setSelection(VisibleSelection(pos.deepEquivalent(), pos.deepEquivalent(), pos.affinity()), options, align);
     98 }
     99 
    100 void SelectionController::moveTo(const VisiblePosition &base, const VisiblePosition &extent, bool userTriggered)
    101 {
    102     SetSelectionOptions options = CloseTyping | ClearTypingStyle;
    103     if (userTriggered)
    104         options |= UserTriggered;
    105     setSelection(VisibleSelection(base.deepEquivalent(), extent.deepEquivalent(), base.affinity()), options);
    106 }
    107 
    108 void SelectionController::moveTo(const Position &pos, EAffinity affinity, bool userTriggered)
    109 {
    110     SetSelectionOptions options = CloseTyping | ClearTypingStyle;
    111     if (userTriggered)
    112         options |= UserTriggered;
    113     setSelection(VisibleSelection(pos, affinity), options);
    114 }
    115 
    116 void SelectionController::moveTo(const Range *r, EAffinity affinity, bool userTriggered)
    117 {
    118     SetSelectionOptions options = CloseTyping | ClearTypingStyle;
    119     if (userTriggered)
    120         options |= UserTriggered;
    121     VisibleSelection selection = r ? VisibleSelection(r->startPosition(), r->endPosition(), affinity) : VisibleSelection(Position(), Position(), affinity);
    122     setSelection(selection, options);
    123 }
    124 
    125 void SelectionController::moveTo(const Position &base, const Position &extent, EAffinity affinity, bool userTriggered)
    126 {
    127     SetSelectionOptions options = CloseTyping | ClearTypingStyle;
    128     if (userTriggered)
    129         options |= UserTriggered;
    130     setSelection(VisibleSelection(base, extent, affinity), options);
    131 }
    132 
    133 void SelectionController::setSelection(const VisibleSelection& s, SetSelectionOptions options, CursorAlignOnScroll align, TextGranularity granularity, DirectionalityPolicy directionalityPolicy)
    134 {
    135     m_granularity = granularity;
    136 
    137     bool closeTyping = options & CloseTyping;
    138     bool shouldClearTypingStyle = options & ClearTypingStyle;
    139     bool userTriggered = options & UserTriggered;
    140 
    141     setIsDirectional(directionalityPolicy == MakeDirectionalSelection);
    142 
    143     if (m_isDragCaretController) {
    144         invalidateCaretRect();
    145         m_selection = s;
    146         m_caretRectNeedsUpdate = true;
    147         invalidateCaretRect();
    148         updateCaretRect();
    149         return;
    150     }
    151     if (!m_frame) {
    152         m_selection = s;
    153         return;
    154     }
    155 
    156     // <http://bugs.webkit.org/show_bug.cgi?id=23464>: Infinite recursion at SelectionController::setSelection
    157     // if document->frame() == m_frame we can get into an infinite loop
    158     if (s.base().anchorNode()) {
    159         Document* document = s.base().anchorNode()->document();
    160         if (document && document->frame() && document->frame() != m_frame && document != m_frame->document()) {
    161             document->frame()->selection()->setSelection(s, options);
    162             return;
    163         }
    164     }
    165 
    166     if (closeTyping)
    167         TypingCommand::closeTyping(m_frame->editor()->lastEditCommand());
    168 
    169     if (shouldClearTypingStyle)
    170         clearTypingStyle();
    171 
    172     if (m_selection == s) {
    173         // Even if selection was not changed, selection offsets may have been changed.
    174         notifyRendererOfSelectionChange(userTriggered);
    175         return;
    176     }
    177 
    178     VisibleSelection oldSelection = m_selection;
    179 
    180     m_selection = s;
    181 
    182     m_caretRectNeedsUpdate = true;
    183 
    184     if (!s.isNone())
    185         setFocusedNodeIfNeeded();
    186 
    187     updateAppearance();
    188 
    189     // Always clear the x position used for vertical arrow navigation.
    190     // It will be restored by the vertical arrow navigation code if necessary.
    191     m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation;
    192     selectFrameElementInParentIfFullySelected();
    193     notifyRendererOfSelectionChange(userTriggered);
    194     m_frame->editor()->respondToChangedSelection(oldSelection, options);
    195     if (userTriggered) {
    196         ScrollAlignment alignment;
    197 
    198         if (m_frame->editor()->behavior().shouldCenterAlignWhenSelectionIsRevealed())
    199             alignment = (align == AlignCursorOnScrollAlways) ? ScrollAlignment::alignCenterAlways : ScrollAlignment::alignCenterIfNeeded;
    200         else
    201             alignment = (align == AlignCursorOnScrollAlways) ? ScrollAlignment::alignTopAlways : ScrollAlignment::alignToEdgeIfNeeded;
    202 
    203         revealSelection(alignment, true);
    204     }
    205 
    206     notifyAccessibilityForSelectionChange();
    207     m_frame->document()->enqueueDocumentEvent(Event::create(eventNames().selectionchangeEvent, false, false));
    208 }
    209 
    210 static bool removingNodeRemovesPosition(Node* node, const Position& position)
    211 {
    212     if (!position.anchorNode())
    213         return false;
    214 
    215     if (position.anchorNode() == node)
    216         return true;
    217 
    218     if (!node->isElementNode())
    219         return false;
    220 
    221     Element* element = static_cast<Element*>(node);
    222     return element->contains(position.anchorNode()) || element->contains(position.anchorNode()->shadowAncestorNode());
    223 }
    224 
    225 void SelectionController::nodeWillBeRemoved(Node *node)
    226 {
    227     if (isNone())
    228         return;
    229 
    230     // There can't be a selection inside a fragment, so if a fragment's node is being removed,
    231     // the selection in the document that created the fragment needs no adjustment.
    232     if (node && highestAncestor(node)->nodeType() == Node::DOCUMENT_FRAGMENT_NODE)
    233         return;
    234 
    235     respondToNodeModification(node, removingNodeRemovesPosition(node, m_selection.base()), removingNodeRemovesPosition(node, m_selection.extent()),
    236         removingNodeRemovesPosition(node, m_selection.start()), removingNodeRemovesPosition(node, m_selection.end()));
    237 }
    238 
    239 void SelectionController::respondToNodeModification(Node* node, bool baseRemoved, bool extentRemoved, bool startRemoved, bool endRemoved)
    240 {
    241     bool clearRenderTreeSelection = false;
    242     bool clearDOMTreeSelection = false;
    243 
    244     if (startRemoved || endRemoved) {
    245         // FIXME: When endpoints are removed, we should just alter the selection, instead of blowing it away.
    246         clearRenderTreeSelection = true;
    247         clearDOMTreeSelection = true;
    248     } else if (baseRemoved || extentRemoved) {
    249         // The base and/or extent are about to be removed, but the start and end aren't.
    250         // Change the base and extent to the start and end, but don't re-validate the
    251         // selection, since doing so could move the start and end into the node
    252         // that is about to be removed.
    253         if (m_selection.isBaseFirst())
    254             m_selection.setWithoutValidation(m_selection.start(), m_selection.end());
    255         else
    256             m_selection.setWithoutValidation(m_selection.end(), m_selection.start());
    257     } else if (RefPtr<Range> range = m_selection.firstRange()) {
    258         ExceptionCode ec = 0;
    259         Range::CompareResults compareResult = range->compareNode(node, ec);
    260         if (!ec && (compareResult == Range::NODE_BEFORE_AND_AFTER || compareResult == Range::NODE_INSIDE)) {
    261             // If we did nothing here, when this node's renderer was destroyed, the rect that it
    262             // occupied would be invalidated, but, selection gaps that change as a result of
    263             // the removal wouldn't be invalidated.
    264             // FIXME: Don't do so much unnecessary invalidation.
    265             clearRenderTreeSelection = true;
    266         }
    267     }
    268 
    269     if (clearRenderTreeSelection) {
    270         RefPtr<Document> document = m_selection.start().anchorNode()->document();
    271         document->updateStyleIfNeeded();
    272         if (RenderView* view = toRenderView(document->renderer()))
    273             view->clearSelection();
    274     }
    275 
    276     if (clearDOMTreeSelection)
    277         setSelection(VisibleSelection(), 0);
    278 }
    279 
    280 enum EndPointType { EndPointIsStart, EndPointIsEnd };
    281 
    282 static bool shouldRemovePositionAfterAdoptingTextReplacement(Position& position, EndPointType type, CharacterData* node, unsigned offset, unsigned oldLength, unsigned newLength)
    283 {
    284     if (!position.anchorNode() || position.anchorNode() != node || position.anchorType() != Position::PositionIsOffsetInAnchor)
    285         return false;
    286 
    287     ASSERT(position.offsetInContainerNode() >= 0);
    288     unsigned positionOffset = static_cast<unsigned>(position.offsetInContainerNode());
    289     if (positionOffset > offset && positionOffset < offset + oldLength)
    290         return true;
    291 
    292     // Adjust the offset if the position is after or at the end of the deleted contents (positionOffset >= offset + oldLength)
    293     // to avoid having a stale offset except when the position is the end of selection and nothing is deleted, in which case,
    294     // adjusting offset results in incorrectly extending the selection until the end of newly inserted contents.
    295     if ((positionOffset > offset + oldLength) || (positionOffset == offset + oldLength && (type == EndPointIsStart || oldLength)))
    296         position.moveToOffset(positionOffset - oldLength + newLength);
    297 
    298     return false;
    299 }
    300 
    301 void SelectionController::textWillBeReplaced(CharacterData* node, unsigned offset, unsigned oldLength, unsigned newLength)
    302 {
    303     // The fragment check is a performance optimization. See http://trac.webkit.org/changeset/30062.
    304     if (isNone() || !node || highestAncestor(node)->nodeType() == Node::DOCUMENT_FRAGMENT_NODE)
    305         return;
    306 
    307     Position base = m_selection.base();
    308     Position extent = m_selection.extent();
    309     Position start = m_selection.start();
    310     Position end = m_selection.end();
    311     bool shouldRemoveBase = shouldRemovePositionAfterAdoptingTextReplacement(base, m_selection.isBaseFirst() ? EndPointIsStart : EndPointIsEnd, node, offset, oldLength, newLength);
    312     bool shouldRemoveExtent = shouldRemovePositionAfterAdoptingTextReplacement(extent, m_selection.isBaseFirst() ? EndPointIsEnd : EndPointIsStart, node, offset, oldLength, newLength);
    313     bool shouldRemoveStart = shouldRemovePositionAfterAdoptingTextReplacement(start, EndPointIsStart, node, offset, oldLength, newLength);
    314     bool shouldRemoveEnd = shouldRemovePositionAfterAdoptingTextReplacement(end, EndPointIsEnd, node, offset, oldLength, newLength);
    315 
    316     if ((base != m_selection.base() || extent != m_selection.extent() || start != m_selection.start() || end != m_selection.end())
    317         && !shouldRemoveStart && !shouldRemoveEnd) {
    318         VisibleSelection newSelection;
    319         if (!shouldRemoveBase && !shouldRemoveExtent)
    320             newSelection.setWithoutValidation(base, extent);
    321         else {
    322             if (newSelection.isBaseFirst())
    323                 newSelection.setWithoutValidation(start, end);
    324             else
    325                 newSelection.setWithoutValidation(end, start);
    326         }
    327         m_frame->document()->updateLayout();
    328         setSelection(newSelection, 0);
    329         return;
    330     }
    331 
    332     respondToNodeModification(node, shouldRemoveBase, shouldRemoveExtent, shouldRemoveStart, shouldRemoveEnd);
    333 }
    334 
    335 void SelectionController::setIsDirectional(bool isDirectional)
    336 {
    337     m_isDirectional = !m_frame || m_frame->editor()->behavior().shouldConsiderSelectionAsDirectional() || isDirectional;
    338 }
    339 
    340 TextDirection SelectionController::directionOfEnclosingBlock()
    341 {
    342     return WebCore::directionOfEnclosingBlock(m_selection.extent());
    343 }
    344 
    345 void SelectionController::willBeModified(EAlteration alter, SelectionDirection direction)
    346 {
    347     if (alter != AlterationExtend)
    348         return;
    349 
    350     Position start = m_selection.start();
    351     Position end = m_selection.end();
    352 
    353     bool baseIsStart = true;
    354 
    355     if (m_isDirectional) {
    356         // Make base and extent match start and end so we extend the user-visible selection.
    357         // This only matters for cases where base and extend point to different positions than
    358         // start and end (e.g. after a double-click to select a word).
    359         if (m_selection.isBaseFirst())
    360             baseIsStart = true;
    361         else
    362             baseIsStart = false;
    363     } else {
    364         switch (direction) {
    365         case DirectionRight:
    366             if (directionOfEnclosingBlock() == LTR)
    367                 baseIsStart = true;
    368             else
    369                 baseIsStart = false;
    370             break;
    371         case DirectionForward:
    372             baseIsStart = true;
    373             break;
    374         case DirectionLeft:
    375             if (directionOfEnclosingBlock() == LTR)
    376                 baseIsStart = false;
    377             else
    378                 baseIsStart = true;
    379             break;
    380         case DirectionBackward:
    381             baseIsStart = false;
    382             break;
    383         }
    384     }
    385     if (baseIsStart) {
    386         m_selection.setBase(start);
    387         m_selection.setExtent(end);
    388     } else {
    389         m_selection.setBase(end);
    390         m_selection.setExtent(start);
    391     }
    392 }
    393 
    394 VisiblePosition SelectionController::positionForPlatform(bool isGetStart) const
    395 {
    396     Settings* settings = m_frame ? m_frame->settings() : 0;
    397     if (settings && settings->editingBehaviorType() == EditingMacBehavior)
    398         return isGetStart ? m_selection.visibleStart() : m_selection.visibleEnd();
    399     // Linux and Windows always extend selections from the extent endpoint.
    400     // FIXME: VisibleSelection should be fixed to ensure as an invariant that
    401     // base/extent always point to the same nodes as start/end, but which points
    402     // to which depends on the value of isBaseFirst. Then this can be changed
    403     // to just return m_sel.extent().
    404     return m_selection.isBaseFirst() ? m_selection.visibleEnd() : m_selection.visibleStart();
    405 }
    406 
    407 VisiblePosition SelectionController::startForPlatform() const
    408 {
    409     return positionForPlatform(true);
    410 }
    411 
    412 VisiblePosition SelectionController::endForPlatform() const
    413 {
    414     return positionForPlatform(false);
    415 }
    416 
    417 VisiblePosition SelectionController::modifyExtendingRight(TextGranularity granularity)
    418 {
    419     VisiblePosition pos(m_selection.extent(), m_selection.affinity());
    420 
    421     // The difference between modifyExtendingRight and modifyExtendingForward is:
    422     // modifyExtendingForward always extends forward logically.
    423     // modifyExtendingRight behaves the same as modifyExtendingForward except for extending character or word,
    424     // it extends forward logically if the enclosing block is LTR direction,
    425     // but it extends backward logically if the enclosing block is RTL direction.
    426     switch (granularity) {
    427     case CharacterGranularity:
    428         if (directionOfEnclosingBlock() == LTR)
    429             pos = pos.next(CannotCrossEditingBoundary);
    430         else
    431             pos = pos.previous(CannotCrossEditingBoundary);
    432         break;
    433     case WordGranularity:
    434         if (directionOfEnclosingBlock() == LTR)
    435             pos = nextWordPosition(pos);
    436         else
    437             pos = previousWordPosition(pos);
    438         break;
    439     case LineBoundary:
    440         if (directionOfEnclosingBlock() == LTR)
    441             pos = modifyExtendingForward(granularity);
    442         else
    443             pos = modifyExtendingBackward(granularity);
    444         break;
    445     case SentenceGranularity:
    446     case LineGranularity:
    447     case ParagraphGranularity:
    448     case SentenceBoundary:
    449     case ParagraphBoundary:
    450     case DocumentBoundary:
    451         // FIXME: implement all of the above?
    452         pos = modifyExtendingForward(granularity);
    453         break;
    454     case WebKitVisualWordGranularity:
    455         break;
    456     }
    457     return pos;
    458 }
    459 
    460 VisiblePosition SelectionController::modifyExtendingForward(TextGranularity granularity)
    461 {
    462     VisiblePosition pos(m_selection.extent(), m_selection.affinity());
    463     switch (granularity) {
    464     case CharacterGranularity:
    465         pos = pos.next(CannotCrossEditingBoundary);
    466         break;
    467     case WordGranularity:
    468         pos = nextWordPosition(pos);
    469         break;
    470     case SentenceGranularity:
    471         pos = nextSentencePosition(pos);
    472         break;
    473     case LineGranularity:
    474         pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));
    475         break;
    476     case ParagraphGranularity:
    477         pos = nextParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
    478         break;
    479     case SentenceBoundary:
    480         pos = endOfSentence(endForPlatform());
    481         break;
    482     case LineBoundary:
    483         pos = logicalEndOfLine(endForPlatform());
    484         break;
    485     case ParagraphBoundary:
    486         pos = endOfParagraph(endForPlatform());
    487         break;
    488     case DocumentBoundary:
    489         pos = endForPlatform();
    490         if (isEditablePosition(pos.deepEquivalent()))
    491             pos = endOfEditableContent(pos);
    492         else
    493             pos = endOfDocument(pos);
    494         break;
    495     case WebKitVisualWordGranularity:
    496         break;
    497     }
    498 
    499     return pos;
    500 }
    501 
    502 VisiblePosition SelectionController::modifyMovingRight(TextGranularity granularity)
    503 {
    504     VisiblePosition pos;
    505     switch (granularity) {
    506     case CharacterGranularity:
    507         if (isRange()) {
    508             if (directionOfEnclosingBlock() == LTR)
    509                 pos = VisiblePosition(m_selection.end(), m_selection.affinity());
    510             else
    511                 pos = VisiblePosition(m_selection.start(), m_selection.affinity());
    512         } else
    513             pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).right(true);
    514         break;
    515     case WordGranularity:
    516     case SentenceGranularity:
    517     case LineGranularity:
    518     case ParagraphGranularity:
    519     case SentenceBoundary:
    520     case ParagraphBoundary:
    521     case DocumentBoundary:
    522         // FIXME: Implement all of the above.
    523         pos = modifyMovingForward(granularity);
    524         break;
    525     case LineBoundary:
    526         pos = rightBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
    527         break;
    528     case WebKitVisualWordGranularity:
    529         pos = rightWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
    530         break;
    531     }
    532     return pos;
    533 }
    534 
    535 VisiblePosition SelectionController::modifyMovingForward(TextGranularity granularity)
    536 {
    537     VisiblePosition pos;
    538     // FIXME: Stay in editable content for the less common granularities.
    539     switch (granularity) {
    540     case CharacterGranularity:
    541         if (isRange())
    542             pos = VisiblePosition(m_selection.end(), m_selection.affinity());
    543         else
    544             pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).next(CannotCrossEditingBoundary);
    545         break;
    546     case WordGranularity:
    547         pos = nextWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
    548         break;
    549     case SentenceGranularity:
    550         pos = nextSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
    551         break;
    552     case LineGranularity: {
    553         // down-arrowing from a range selection that ends at the start of a line needs
    554         // to leave the selection at that line start (no need to call nextLinePosition!)
    555         pos = endForPlatform();
    556         if (!isRange() || !isStartOfLine(pos))
    557             pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(START));
    558         break;
    559     }
    560     case ParagraphGranularity:
    561         pos = nextParagraphPosition(endForPlatform(), xPosForVerticalArrowNavigation(START));
    562         break;
    563     case SentenceBoundary:
    564         pos = endOfSentence(endForPlatform());
    565         break;
    566     case LineBoundary:
    567         pos = logicalEndOfLine(endForPlatform());
    568         break;
    569     case ParagraphBoundary:
    570         pos = endOfParagraph(endForPlatform());
    571         break;
    572     case DocumentBoundary:
    573         pos = endForPlatform();
    574         if (isEditablePosition(pos.deepEquivalent()))
    575             pos = endOfEditableContent(pos);
    576         else
    577             pos = endOfDocument(pos);
    578         break;
    579     case WebKitVisualWordGranularity:
    580         break;
    581     }
    582     return pos;
    583 }
    584 
    585 VisiblePosition SelectionController::modifyExtendingLeft(TextGranularity granularity)
    586 {
    587     VisiblePosition pos(m_selection.extent(), m_selection.affinity());
    588 
    589     // The difference between modifyExtendingLeft and modifyExtendingBackward is:
    590     // modifyExtendingBackward always extends backward logically.
    591     // modifyExtendingLeft behaves the same as modifyExtendingBackward except for extending character or word,
    592     // it extends backward logically if the enclosing block is LTR direction,
    593     // but it extends forward logically if the enclosing block is RTL direction.
    594     switch (granularity) {
    595     case CharacterGranularity:
    596         if (directionOfEnclosingBlock() == LTR)
    597             pos = pos.previous(CannotCrossEditingBoundary);
    598         else
    599             pos = pos.next(CannotCrossEditingBoundary);
    600         break;
    601     case WordGranularity:
    602         if (directionOfEnclosingBlock() == LTR)
    603             pos = previousWordPosition(pos);
    604         else
    605             pos = nextWordPosition(pos);
    606         break;
    607     case LineBoundary:
    608         if (directionOfEnclosingBlock() == LTR)
    609             pos = modifyExtendingBackward(granularity);
    610         else
    611             pos = modifyExtendingForward(granularity);
    612         break;
    613     case SentenceGranularity:
    614     case LineGranularity:
    615     case ParagraphGranularity:
    616     case SentenceBoundary:
    617     case ParagraphBoundary:
    618     case DocumentBoundary:
    619         pos = modifyExtendingBackward(granularity);
    620         break;
    621     case WebKitVisualWordGranularity:
    622         break;
    623     }
    624     return pos;
    625 }
    626 
    627 VisiblePosition SelectionController::modifyExtendingBackward(TextGranularity granularity)
    628 {
    629     VisiblePosition pos(m_selection.extent(), m_selection.affinity());
    630 
    631     // Extending a selection backward by word or character from just after a table selects
    632     // the table.  This "makes sense" from the user perspective, esp. when deleting.
    633     // It was done here instead of in VisiblePosition because we want VPs to iterate
    634     // over everything.
    635     switch (granularity) {
    636     case CharacterGranularity:
    637         pos = pos.previous(CannotCrossEditingBoundary);
    638         break;
    639     case WordGranularity:
    640         pos = previousWordPosition(pos);
    641         break;
    642     case SentenceGranularity:
    643         pos = previousSentencePosition(pos);
    644         break;
    645     case LineGranularity:
    646         pos = previousLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));
    647         break;
    648     case ParagraphGranularity:
    649         pos = previousParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
    650         break;
    651     case SentenceBoundary:
    652         pos = startOfSentence(startForPlatform());
    653         break;
    654     case LineBoundary:
    655         pos = logicalStartOfLine(startForPlatform());
    656         break;
    657     case ParagraphBoundary:
    658         pos = startOfParagraph(startForPlatform());
    659         break;
    660     case DocumentBoundary:
    661         pos = startForPlatform();
    662         if (isEditablePosition(pos.deepEquivalent()))
    663             pos = startOfEditableContent(pos);
    664         else
    665             pos = startOfDocument(pos);
    666         break;
    667     case WebKitVisualWordGranularity:
    668         break;
    669     }
    670     return pos;
    671 }
    672 
    673 VisiblePosition SelectionController::modifyMovingLeft(TextGranularity granularity)
    674 {
    675     VisiblePosition pos;
    676     switch (granularity) {
    677     case CharacterGranularity:
    678         if (isRange())
    679             if (directionOfEnclosingBlock() == LTR)
    680                 pos = VisiblePosition(m_selection.start(), m_selection.affinity());
    681             else
    682                 pos = VisiblePosition(m_selection.end(), m_selection.affinity());
    683         else
    684             pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).left(true);
    685         break;
    686     case WordGranularity:
    687     case SentenceGranularity:
    688     case LineGranularity:
    689     case ParagraphGranularity:
    690     case SentenceBoundary:
    691     case ParagraphBoundary:
    692     case DocumentBoundary:
    693         // FIXME: Implement all of the above.
    694         pos = modifyMovingBackward(granularity);
    695         break;
    696     case LineBoundary:
    697         pos = leftBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
    698         break;
    699     case WebKitVisualWordGranularity:
    700         pos = leftWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
    701         break;
    702     }
    703     return pos;
    704 }
    705 
    706 VisiblePosition SelectionController::modifyMovingBackward(TextGranularity granularity)
    707 {
    708     VisiblePosition pos;
    709     switch (granularity) {
    710     case CharacterGranularity:
    711         if (isRange())
    712             pos = VisiblePosition(m_selection.start(), m_selection.affinity());
    713         else
    714             pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).previous(CannotCrossEditingBoundary);
    715         break;
    716     case WordGranularity:
    717         pos = previousWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
    718         break;
    719     case SentenceGranularity:
    720         pos = previousSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
    721         break;
    722     case LineGranularity:
    723         pos = previousLinePosition(startForPlatform(), xPosForVerticalArrowNavigation(START));
    724         break;
    725     case ParagraphGranularity:
    726         pos = previousParagraphPosition(startForPlatform(), xPosForVerticalArrowNavigation(START));
    727         break;
    728     case SentenceBoundary:
    729         pos = startOfSentence(startForPlatform());
    730         break;
    731     case LineBoundary:
    732         pos = logicalStartOfLine(startForPlatform());
    733         break;
    734     case ParagraphBoundary:
    735         pos = startOfParagraph(startForPlatform());
    736         break;
    737     case DocumentBoundary:
    738         pos = startForPlatform();
    739         if (isEditablePosition(pos.deepEquivalent()))
    740             pos = startOfEditableContent(pos);
    741         else
    742             pos = startOfDocument(pos);
    743         break;
    744     case WebKitVisualWordGranularity:
    745         break;
    746     }
    747     return pos;
    748 }
    749 
    750 static bool isBoundary(TextGranularity granularity)
    751 {
    752     return granularity == LineBoundary || granularity == ParagraphBoundary || granularity == DocumentBoundary;
    753 }
    754 
    755 bool SelectionController::modify(EAlteration alter, SelectionDirection direction, TextGranularity granularity, bool userTriggered)
    756 {
    757     if (userTriggered) {
    758         SelectionController trialSelectionController;
    759         trialSelectionController.setSelection(m_selection);
    760         trialSelectionController.setIsDirectional(m_isDirectional);
    761         trialSelectionController.modify(alter, direction, granularity, false);
    762 
    763         bool change = shouldChangeSelection(trialSelectionController.selection());
    764         if (!change)
    765             return false;
    766     }
    767 
    768     willBeModified(alter, direction);
    769 
    770     bool wasRange = m_selection.isRange();
    771     Position originalStartPosition = m_selection.start();
    772     VisiblePosition position;
    773     switch (direction) {
    774     case DirectionRight:
    775         if (alter == AlterationMove)
    776             position = modifyMovingRight(granularity);
    777         else
    778             position = modifyExtendingRight(granularity);
    779         break;
    780     case DirectionForward:
    781         if (alter == AlterationExtend)
    782             position = modifyExtendingForward(granularity);
    783         else
    784             position = modifyMovingForward(granularity);
    785         break;
    786     case DirectionLeft:
    787         if (alter == AlterationMove)
    788             position = modifyMovingLeft(granularity);
    789         else
    790             position = modifyExtendingLeft(granularity);
    791         break;
    792     case DirectionBackward:
    793         if (alter == AlterationExtend)
    794             position = modifyExtendingBackward(granularity);
    795         else
    796             position = modifyMovingBackward(granularity);
    797         break;
    798     }
    799 
    800     if (position.isNull())
    801         return false;
    802 
    803     if (isSpatialNavigationEnabled(m_frame))
    804         if (!wasRange && alter == AlterationMove && position == originalStartPosition)
    805             return false;
    806 
    807     // Some of the above operations set an xPosForVerticalArrowNavigation.
    808     // Setting a selection will clear it, so save it to possibly restore later.
    809     // Note: the START position type is arbitrary because it is unused, it would be
    810     // the requested position type if there were no xPosForVerticalArrowNavigation set.
    811     int x = xPosForVerticalArrowNavigation(START);
    812 
    813     switch (alter) {
    814     case AlterationMove:
    815         moveTo(position, userTriggered);
    816         break;
    817     case AlterationExtend:
    818         // Standard Mac behavior when extending to a boundary is grow the selection rather than leaving the
    819         // base in place and moving the extent. Matches NSTextView.
    820         if (!m_frame || !m_frame->editor()->behavior().shouldAlwaysGrowSelectionWhenExtendingToBoundary() || m_selection.isCaret() || !isBoundary(granularity))
    821             setExtent(position, userTriggered);
    822         else {
    823             TextDirection textDirection = directionOfEnclosingBlock();
    824             if (direction == DirectionForward || (textDirection == LTR && direction == DirectionRight) || (textDirection == RTL && direction == DirectionLeft))
    825                 setEnd(position, userTriggered);
    826             else
    827                 setStart(position, userTriggered);
    828         }
    829         break;
    830     }
    831 
    832     if (granularity == LineGranularity || granularity == ParagraphGranularity)
    833         m_xPosForVerticalArrowNavigation = x;
    834 
    835     if (userTriggered)
    836         m_granularity = CharacterGranularity;
    837 
    838 
    839     setCaretRectNeedsUpdate();
    840 
    841     setIsDirectional(alter == AlterationExtend);
    842 
    843     return true;
    844 }
    845 
    846 // FIXME: Maybe baseline would be better?
    847 static bool absoluteCaretY(const VisiblePosition &c, int &y)
    848 {
    849     IntRect rect = c.absoluteCaretBounds();
    850     if (rect.isEmpty())
    851         return false;
    852     y = rect.y() + rect.height() / 2;
    853     return true;
    854 }
    855 
    856 bool SelectionController::modify(EAlteration alter, int verticalDistance, bool userTriggered, CursorAlignOnScroll align)
    857 {
    858     if (!verticalDistance)
    859         return false;
    860 
    861     if (userTriggered) {
    862         SelectionController trialSelectionController;
    863         trialSelectionController.setSelection(m_selection);
    864         trialSelectionController.setIsDirectional(m_isDirectional);
    865         trialSelectionController.modify(alter, verticalDistance, false);
    866 
    867         bool change = shouldChangeSelection(trialSelectionController.selection());
    868         if (!change)
    869             return false;
    870     }
    871 
    872     bool up = verticalDistance < 0;
    873     if (up)
    874         verticalDistance = -verticalDistance;
    875 
    876     willBeModified(alter, up ? DirectionBackward : DirectionForward);
    877 
    878     VisiblePosition pos;
    879     int xPos = 0;
    880     switch (alter) {
    881     case AlterationMove:
    882         pos = VisiblePosition(up ? m_selection.start() : m_selection.end(), m_selection.affinity());
    883         xPos = xPosForVerticalArrowNavigation(up ? START : END);
    884         m_selection.setAffinity(up ? UPSTREAM : DOWNSTREAM);
    885         break;
    886     case AlterationExtend:
    887         pos = VisiblePosition(m_selection.extent(), m_selection.affinity());
    888         xPos = xPosForVerticalArrowNavigation(EXTENT);
    889         m_selection.setAffinity(DOWNSTREAM);
    890         break;
    891     }
    892 
    893     int startY;
    894     if (!absoluteCaretY(pos, startY))
    895         return false;
    896     if (up)
    897         startY = -startY;
    898     int lastY = startY;
    899 
    900     VisiblePosition result;
    901     VisiblePosition next;
    902     for (VisiblePosition p = pos; ; p = next) {
    903         next = (up ? previousLinePosition : nextLinePosition)(p, xPos);
    904         if (next.isNull() || next == p)
    905             break;
    906         int nextY;
    907         if (!absoluteCaretY(next, nextY))
    908             break;
    909         if (up)
    910             nextY = -nextY;
    911         if (nextY - startY > verticalDistance)
    912             break;
    913         if (nextY >= lastY) {
    914             lastY = nextY;
    915             result = next;
    916         }
    917     }
    918 
    919     if (result.isNull())
    920         return false;
    921 
    922     switch (alter) {
    923     case AlterationMove:
    924         moveTo(result, userTriggered, align);
    925         break;
    926     case AlterationExtend:
    927         setExtent(result, userTriggered);
    928         break;
    929     }
    930 
    931     if (userTriggered)
    932         m_granularity = CharacterGranularity;
    933 
    934     setIsDirectional(alter == AlterationExtend);
    935 
    936     return true;
    937 }
    938 
    939 int SelectionController::xPosForVerticalArrowNavigation(EPositionType type)
    940 {
    941     int x = 0;
    942 
    943     if (isNone())
    944         return x;
    945 
    946     Position pos;
    947     switch (type) {
    948     case START:
    949         pos = m_selection.start();
    950         break;
    951     case END:
    952         pos = m_selection.end();
    953         break;
    954     case BASE:
    955         pos = m_selection.base();
    956         break;
    957     case EXTENT:
    958         pos = m_selection.extent();
    959         break;
    960     }
    961 
    962     Frame* frame = pos.anchorNode()->document()->frame();
    963     if (!frame)
    964         return x;
    965 
    966     if (m_xPosForVerticalArrowNavigation == NoXPosForVerticalArrowNavigation) {
    967         VisiblePosition visiblePosition(pos, m_selection.affinity());
    968         // VisiblePosition creation can fail here if a node containing the selection becomes visibility:hidden
    969         // after the selection is created and before this function is called.
    970         x = visiblePosition.isNotNull() ? visiblePosition.xOffsetForVerticalNavigation() : 0;
    971         m_xPosForVerticalArrowNavigation = x;
    972     } else
    973         x = m_xPosForVerticalArrowNavigation;
    974 
    975     return x;
    976 }
    977 
    978 void SelectionController::clear()
    979 {
    980     m_granularity = CharacterGranularity;
    981     setSelection(VisibleSelection());
    982 }
    983 
    984 void SelectionController::setStart(const VisiblePosition &pos, bool userTriggered)
    985 {
    986     if (m_selection.isBaseFirst())
    987         setBase(pos, userTriggered);
    988     else
    989         setExtent(pos, userTriggered);
    990 }
    991 
    992 void SelectionController::setEnd(const VisiblePosition &pos, bool userTriggered)
    993 {
    994     if (m_selection.isBaseFirst())
    995         setExtent(pos, userTriggered);
    996     else
    997         setBase(pos, userTriggered);
    998 }
    999 
   1000 void SelectionController::setBase(const VisiblePosition &pos, bool userTriggered)
   1001 {
   1002     SetSelectionOptions options = CloseTyping | ClearTypingStyle;
   1003     if (userTriggered)
   1004         options |= UserTriggered;
   1005     setSelection(VisibleSelection(pos.deepEquivalent(), m_selection.extent(), pos.affinity()), options);
   1006 }
   1007 
   1008 void SelectionController::setExtent(const VisiblePosition &pos, bool userTriggered)
   1009 {
   1010     SetSelectionOptions options = CloseTyping | ClearTypingStyle;
   1011     if (userTriggered)
   1012         options |= UserTriggered;
   1013     setSelection(VisibleSelection(m_selection.base(), pos.deepEquivalent(), pos.affinity()), options);
   1014 }
   1015 
   1016 void SelectionController::setBase(const Position &pos, EAffinity affinity, bool userTriggered)
   1017 {
   1018     SetSelectionOptions options = CloseTyping | ClearTypingStyle;
   1019     if (userTriggered)
   1020         options |= UserTriggered;
   1021     setSelection(VisibleSelection(pos, m_selection.extent(), affinity), options);
   1022 }
   1023 
   1024 void SelectionController::setExtent(const Position &pos, EAffinity affinity, bool userTriggered)
   1025 {
   1026     SetSelectionOptions options = CloseTyping | ClearTypingStyle;
   1027     if (userTriggered)
   1028         options |= UserTriggered;
   1029     setSelection(VisibleSelection(m_selection.base(), pos, affinity), options);
   1030 }
   1031 
   1032 void SelectionController::setCaretRectNeedsUpdate(bool flag)
   1033 {
   1034     m_caretRectNeedsUpdate = flag;
   1035 }
   1036 
   1037 void SelectionController::updateCaretRect()
   1038 {
   1039     if (isNone() || !m_selection.start().anchorNode()->inDocument() || !m_selection.end().anchorNode()->inDocument()) {
   1040         m_caretRect = IntRect();
   1041         return;
   1042     }
   1043 
   1044     m_selection.start().anchorNode()->document()->updateStyleIfNeeded();
   1045 
   1046     m_caretRect = IntRect();
   1047 
   1048     if (isCaret()) {
   1049         VisiblePosition pos(m_selection.start(), m_selection.affinity());
   1050         if (pos.isNotNull()) {
   1051             ASSERT(pos.deepEquivalent().deprecatedNode()->renderer());
   1052 
   1053             // First compute a rect local to the renderer at the selection start
   1054             RenderObject* renderer;
   1055             IntRect localRect = pos.localCaretRect(renderer);
   1056 
   1057             // Get the renderer that will be responsible for painting the caret (which
   1058             // is either the renderer we just found, or one of its containers)
   1059             RenderObject* caretPainter = caretRenderer();
   1060 
   1061             // Compute an offset between the renderer and the caretPainter
   1062             bool unrooted = false;
   1063             while (renderer != caretPainter) {
   1064                 RenderObject* containerObject = renderer->container();
   1065                 if (!containerObject) {
   1066                     unrooted = true;
   1067                     break;
   1068                 }
   1069                 localRect.move(renderer->offsetFromContainer(containerObject, localRect.location()));
   1070                 renderer = containerObject;
   1071             }
   1072 
   1073             if (!unrooted)
   1074                 m_caretRect = localRect;
   1075 
   1076             m_absCaretBoundsDirty = true;
   1077         }
   1078     }
   1079 
   1080     m_caretRectNeedsUpdate = false;
   1081 }
   1082 
   1083 RenderObject* SelectionController::caretRenderer() const
   1084 {
   1085     Node* node = m_selection.start().deprecatedNode();
   1086     if (!node)
   1087         return 0;
   1088 
   1089     RenderObject* renderer = node->renderer();
   1090     if (!renderer)
   1091         return 0;
   1092 
   1093     // if caretNode is a block and caret is inside it then caret should be painted by that block
   1094     bool paintedByBlock = renderer->isBlockFlow() && caretRendersInsideNode(node);
   1095     return paintedByBlock ? renderer : renderer->containingBlock();
   1096 }
   1097 
   1098 IntRect SelectionController::localCaretRect()
   1099 {
   1100     if (m_caretRectNeedsUpdate)
   1101         updateCaretRect();
   1102 
   1103     return m_caretRect;
   1104 }
   1105 
   1106 IntRect SelectionController::absoluteBoundsForLocalRect(const IntRect& rect) const
   1107 {
   1108     RenderObject* caretPainter = caretRenderer();
   1109     if (!caretPainter)
   1110         return IntRect();
   1111 
   1112     IntRect localRect(rect);
   1113     if (caretPainter->isBox())
   1114         toRenderBox(caretPainter)->flipForWritingMode(localRect);
   1115     return caretPainter->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();
   1116 }
   1117 
   1118 IntRect SelectionController::absoluteCaretBounds()
   1119 {
   1120     recomputeCaretRect();
   1121     return m_absCaretBounds;
   1122 }
   1123 
   1124 static IntRect repaintRectForCaret(IntRect caret)
   1125 {
   1126     if (caret.isEmpty())
   1127         return IntRect();
   1128     // Ensure that the dirty rect intersects the block that paints the caret even in the case where
   1129     // the caret itself is just outside the block. See <https://bugs.webkit.org/show_bug.cgi?id=19086>.
   1130     caret.inflateX(1);
   1131     return caret;
   1132 }
   1133 
   1134 IntRect SelectionController::caretRepaintRect() const
   1135 {
   1136     return absoluteBoundsForLocalRect(repaintRectForCaret(localCaretRectForPainting()));
   1137 }
   1138 
   1139 bool SelectionController::recomputeCaretRect()
   1140 {
   1141     if (!m_caretRectNeedsUpdate)
   1142         return false;
   1143 
   1144     if (!m_frame)
   1145         return false;
   1146 
   1147     FrameView* v = m_frame->document()->view();
   1148     if (!v)
   1149         return false;
   1150 
   1151     IntRect oldRect = m_caretRect;
   1152     IntRect newRect = localCaretRect();
   1153     if (oldRect == newRect && !m_absCaretBoundsDirty)
   1154         return false;
   1155 
   1156     IntRect oldAbsCaretBounds = m_absCaretBounds;
   1157     // FIXME: Rename m_caretRect to m_localCaretRect.
   1158     m_absCaretBounds = absoluteBoundsForLocalRect(m_caretRect);
   1159     m_absCaretBoundsDirty = false;
   1160 
   1161     if (oldAbsCaretBounds == m_absCaretBounds)
   1162         return false;
   1163 
   1164     IntRect oldAbsoluteCaretRepaintBounds = m_absoluteCaretRepaintBounds;
   1165     // We believe that we need to inflate the local rect before transforming it to obtain the repaint bounds.
   1166     m_absoluteCaretRepaintBounds = caretRepaintRect();
   1167 
   1168 #if ENABLE(TEXT_CARET)
   1169     if (RenderView* view = toRenderView(m_frame->document()->renderer())) {
   1170         // FIXME: make caret repainting container-aware.
   1171         view->repaintRectangleInViewAndCompositedLayers(oldAbsoluteCaretRepaintBounds, false);
   1172         if (shouldRepaintCaret(view))
   1173             view->repaintRectangleInViewAndCompositedLayers(m_absoluteCaretRepaintBounds, false);
   1174     }
   1175 #endif
   1176     return true;
   1177 }
   1178 
   1179 bool SelectionController::shouldRepaintCaret(const RenderView* view) const
   1180 {
   1181     ASSERT(view);
   1182     Frame* frame = view->frameView() ? view->frameView()->frame() : 0; // The frame where the selection started.
   1183     bool caretBrowsing = frame && frame->settings() && frame->settings()->caretBrowsingEnabled();
   1184     return (caretBrowsing || isContentEditable());
   1185 }
   1186 
   1187 void SelectionController::invalidateCaretRect()
   1188 {
   1189     if (!isCaret())
   1190         return;
   1191 
   1192     Document* d = m_selection.start().anchorNode()->document();
   1193 
   1194     // recomputeCaretRect will always return false for the drag caret,
   1195     // because its m_frame is always 0.
   1196     bool caretRectChanged = recomputeCaretRect();
   1197 
   1198     // EDIT FIXME: This is an unfortunate hack.
   1199     // Basically, we can't trust this layout position since we
   1200     // can't guarantee that the check to see if we are in unrendered
   1201     // content will work at this point. We may have to wait for
   1202     // a layout and re-render of the document to happen. So, resetting this
   1203     // flag will cause another caret layout to happen the first time
   1204     // that we try to paint the caret after this call. That one will work since
   1205     // it happens after the document has accounted for any editing
   1206     // changes which may have been done.
   1207     // And, we need to leave this layout here so the caret moves right
   1208     // away after clicking.
   1209     m_caretRectNeedsUpdate = true;
   1210 
   1211     if (!caretRectChanged) {
   1212         RenderView* view = toRenderView(d->renderer());
   1213         if (view && shouldRepaintCaret(view))
   1214             view->repaintRectangleInViewAndCompositedLayers(caretRepaintRect(), false);
   1215     }
   1216 }
   1217 
   1218 void SelectionController::paintCaret(GraphicsContext* context, int tx, int ty, const IntRect& clipRect)
   1219 {
   1220 #if ENABLE(TEXT_CARET)
   1221     if (!m_caretVisible)
   1222         return;
   1223     if (!m_caretPaint)
   1224         return;
   1225     if (!m_selection.isCaret())
   1226         return;
   1227 
   1228     IntRect drawingRect = localCaretRectForPainting();
   1229     if (caretRenderer() && caretRenderer()->isBox())
   1230         toRenderBox(caretRenderer())->flipForWritingMode(drawingRect);
   1231     drawingRect.move(tx, ty);
   1232     IntRect caret = intersection(drawingRect, clipRect);
   1233     if (caret.isEmpty())
   1234         return;
   1235 
   1236     Color caretColor = Color::black;
   1237     ColorSpace colorSpace = ColorSpaceDeviceRGB;
   1238     Element* element = rootEditableElement();
   1239     if (element && element->renderer()) {
   1240         caretColor = element->renderer()->style()->visitedDependentColor(CSSPropertyColor);
   1241         colorSpace = element->renderer()->style()->colorSpace();
   1242     }
   1243 
   1244     context->fillRect(caret, caretColor, colorSpace);
   1245 #else
   1246     UNUSED_PARAM(context);
   1247     UNUSED_PARAM(tx);
   1248     UNUSED_PARAM(ty);
   1249     UNUSED_PARAM(clipRect);
   1250 #endif
   1251 }
   1252 
   1253 void SelectionController::debugRenderer(RenderObject *r, bool selected) const
   1254 {
   1255     if (r->node()->isElementNode()) {
   1256         Element* element = static_cast<Element *>(r->node());
   1257         fprintf(stderr, "%s%s\n", selected ? "==> " : "    ", element->localName().string().utf8().data());
   1258     } else if (r->isText()) {
   1259         RenderText* textRenderer = toRenderText(r);
   1260         if (!textRenderer->textLength() || !textRenderer->firstTextBox()) {
   1261             fprintf(stderr, "%s#text (empty)\n", selected ? "==> " : "    ");
   1262             return;
   1263         }
   1264 
   1265         static const int max = 36;
   1266         String text = textRenderer->text();
   1267         int textLength = text.length();
   1268         if (selected) {
   1269             int offset = 0;
   1270             if (r->node() == m_selection.start().containerNode())
   1271                 offset = m_selection.start().computeOffsetInContainerNode();
   1272             else if (r->node() == m_selection.end().containerNode())
   1273                 offset = m_selection.end().computeOffsetInContainerNode();
   1274 
   1275             int pos;
   1276             InlineTextBox* box = textRenderer->findNextInlineTextBox(offset, pos);
   1277             text = text.substring(box->start(), box->len());
   1278 
   1279             String show;
   1280             int mid = max / 2;
   1281             int caret = 0;
   1282 
   1283             // text is shorter than max
   1284             if (textLength < max) {
   1285                 show = text;
   1286                 caret = pos;
   1287             } else if (pos - mid < 0) {
   1288                 // too few characters to left
   1289                 show = text.left(max - 3) + "...";
   1290                 caret = pos;
   1291             } else if (pos - mid >= 0 && pos + mid <= textLength) {
   1292                 // enough characters on each side
   1293                 show = "..." + text.substring(pos - mid + 3, max - 6) + "...";
   1294                 caret = mid;
   1295             } else {
   1296                 // too few characters on right
   1297                 show = "..." + text.right(max - 3);
   1298                 caret = pos - (textLength - show.length());
   1299             }
   1300 
   1301             show.replace('\n', ' ');
   1302             show.replace('\r', ' ');
   1303             fprintf(stderr, "==> #text : \"%s\" at offset %d\n", show.utf8().data(), pos);
   1304             fprintf(stderr, "           ");
   1305             for (int i = 0; i < caret; i++)
   1306                 fprintf(stderr, " ");
   1307             fprintf(stderr, "^\n");
   1308         } else {
   1309             if ((int)text.length() > max)
   1310                 text = text.left(max - 3) + "...";
   1311             else
   1312                 text = text.left(max);
   1313             fprintf(stderr, "    #text : \"%s\"\n", text.utf8().data());
   1314         }
   1315     }
   1316 }
   1317 
   1318 bool SelectionController::contains(const IntPoint& point)
   1319 {
   1320     Document* document = m_frame->document();
   1321 
   1322     // Treat a collapsed selection like no selection.
   1323     if (!isRange())
   1324         return false;
   1325     if (!document->renderer())
   1326         return false;
   1327 
   1328     HitTestRequest request(HitTestRequest::ReadOnly |
   1329                            HitTestRequest::Active);
   1330     HitTestResult result(point);
   1331     document->renderView()->layer()->hitTest(request, result);
   1332     Node* innerNode = result.innerNode();
   1333     if (!innerNode || !innerNode->renderer())
   1334         return false;
   1335 
   1336     VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(result.localPoint()));
   1337     if (visiblePos.isNull())
   1338         return false;
   1339 
   1340     if (m_selection.visibleStart().isNull() || m_selection.visibleEnd().isNull())
   1341         return false;
   1342 
   1343     Position start(m_selection.visibleStart().deepEquivalent());
   1344     Position end(m_selection.visibleEnd().deepEquivalent());
   1345     Position p(visiblePos.deepEquivalent());
   1346 
   1347     return comparePositions(start, p) <= 0 && comparePositions(p, end) <= 0;
   1348 }
   1349 
   1350 // Workaround for the fact that it's hard to delete a frame.
   1351 // Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
   1352 // Can't do this implicitly as part of every setSelection call because in some contexts it might not be good
   1353 // for the focus to move to another frame. So instead we call it from places where we are selecting with the
   1354 // mouse or the keyboard after setting the selection.
   1355 void SelectionController::selectFrameElementInParentIfFullySelected()
   1356 {
   1357     // Find the parent frame; if there is none, then we have nothing to do.
   1358     Frame* parent = m_frame->tree()->parent();
   1359     if (!parent)
   1360         return;
   1361     Page* page = m_frame->page();
   1362     if (!page)
   1363         return;
   1364 
   1365     // Check if the selection contains the entire frame contents; if not, then there is nothing to do.
   1366     if (!isRange())
   1367         return;
   1368     if (!isStartOfDocument(selection().visibleStart()))
   1369         return;
   1370     if (!isEndOfDocument(selection().visibleEnd()))
   1371         return;
   1372 
   1373     // Get to the <iframe> or <frame> (or even <object>) element in the parent frame.
   1374     Element* ownerElement = m_frame->ownerElement();
   1375     if (!ownerElement)
   1376         return;
   1377     ContainerNode* ownerElementParent = ownerElement->parentNode();
   1378     if (!ownerElementParent)
   1379         return;
   1380 
   1381     // This method's purpose is it to make it easier to select iframes (in order to delete them).  Don't do anything if the iframe isn't deletable.
   1382     if (!ownerElementParent->rendererIsEditable())
   1383         return;
   1384 
   1385     // Create compute positions before and after the element.
   1386     unsigned ownerElementNodeIndex = ownerElement->nodeIndex();
   1387     VisiblePosition beforeOwnerElement(VisiblePosition(Position(ownerElementParent, ownerElementNodeIndex, Position::PositionIsOffsetInAnchor)));
   1388     VisiblePosition afterOwnerElement(VisiblePosition(Position(ownerElementParent, ownerElementNodeIndex + 1, Position::PositionIsOffsetInAnchor), VP_UPSTREAM_IF_POSSIBLE));
   1389 
   1390     // Focus on the parent frame, and then select from before this element to after.
   1391     VisibleSelection newSelection(beforeOwnerElement, afterOwnerElement);
   1392     if (parent->selection()->shouldChangeSelection(newSelection)) {
   1393         page->focusController()->setFocusedFrame(parent);
   1394         parent->selection()->setSelection(newSelection);
   1395     }
   1396 }
   1397 
   1398 void SelectionController::selectAll()
   1399 {
   1400     Document* document = m_frame->document();
   1401 
   1402     if (document->focusedNode() && document->focusedNode()->canSelectAll()) {
   1403         document->focusedNode()->selectAll();
   1404         return;
   1405     }
   1406 
   1407     Node* root = 0;
   1408     if (isContentEditable())
   1409         root = highestEditableRoot(m_selection.start());
   1410     else {
   1411         root = shadowTreeRootNode();
   1412         if (!root)
   1413             root = document->documentElement();
   1414     }
   1415     if (!root)
   1416         return;
   1417     VisibleSelection newSelection(VisibleSelection::selectionFromContentsOfNode(root));
   1418     if (shouldChangeSelection(newSelection))
   1419         setSelection(newSelection);
   1420     selectFrameElementInParentIfFullySelected();
   1421     notifyRendererOfSelectionChange(true);
   1422 }
   1423 
   1424 bool SelectionController::setSelectedRange(Range* range, EAffinity affinity, bool closeTyping)
   1425 {
   1426     if (!range)
   1427         return false;
   1428 
   1429     ExceptionCode ec = 0;
   1430     Node* startContainer = range->startContainer(ec);
   1431     if (ec)
   1432         return false;
   1433 
   1434     Node* endContainer = range->endContainer(ec);
   1435     if (ec)
   1436         return false;
   1437 
   1438     ASSERT(startContainer);
   1439     ASSERT(endContainer);
   1440     ASSERT(startContainer->document() == endContainer->document());
   1441 
   1442     m_frame->document()->updateLayoutIgnorePendingStylesheets();
   1443 
   1444     // Non-collapsed ranges are not allowed to start at the end of a line that is wrapped,
   1445     // they start at the beginning of the next line instead
   1446     bool collapsed = range->collapsed(ec);
   1447     if (ec)
   1448         return false;
   1449 
   1450     int startOffset = range->startOffset(ec);
   1451     if (ec)
   1452         return false;
   1453 
   1454     int endOffset = range->endOffset(ec);
   1455     if (ec)
   1456         return false;
   1457 
   1458     // FIXME: Can we provide extentAffinity?
   1459     VisiblePosition visibleStart(Position(startContainer, startOffset, Position::PositionIsOffsetInAnchor), collapsed ? affinity : DOWNSTREAM);
   1460     VisiblePosition visibleEnd(Position(endContainer, endOffset, Position::PositionIsOffsetInAnchor), SEL_DEFAULT_AFFINITY);
   1461     SetSelectionOptions options = ClearTypingStyle;
   1462     if (closeTyping)
   1463         options |= CloseTyping;
   1464     setSelection(VisibleSelection(visibleStart, visibleEnd), options);
   1465     return true;
   1466 }
   1467 
   1468 bool SelectionController::isInPasswordField() const
   1469 {
   1470     ASSERT(start().isNull() || start().anchorType() == Position::PositionIsOffsetInAnchor
   1471            || start().containerNode() || !start().anchorNode()->shadowAncestorNode());
   1472     Node* startNode = start().containerNode();
   1473     if (!startNode)
   1474         return false;
   1475 
   1476     startNode = startNode->shadowAncestorNode();
   1477     if (!startNode)
   1478         return false;
   1479 
   1480     if (!startNode->hasTagName(inputTag))
   1481         return false;
   1482 
   1483     return static_cast<HTMLInputElement*>(startNode)->isPasswordField();
   1484 }
   1485 
   1486 bool SelectionController::caretRendersInsideNode(Node* node) const
   1487 {
   1488     if (!node)
   1489         return false;
   1490     return !isTableElement(node) && !editingIgnoresContent(node);
   1491 }
   1492 
   1493 void SelectionController::focusedOrActiveStateChanged()
   1494 {
   1495     bool activeAndFocused = isFocusedAndActive();
   1496 
   1497     // Because RenderObject::selectionBackgroundColor() and
   1498     // RenderObject::selectionForegroundColor() check if the frame is active,
   1499     // we have to update places those colors were painted.
   1500     if (RenderView* view = toRenderView(m_frame->document()->renderer()))
   1501         view->repaintRectangleInViewAndCompositedLayers(enclosingIntRect(bounds()));
   1502 
   1503     // Caret appears in the active frame.
   1504     if (activeAndFocused)
   1505         setSelectionFromNone();
   1506     setCaretVisible(activeAndFocused);
   1507 
   1508     // Update for caps lock state
   1509     m_frame->eventHandler()->capsLockStateMayHaveChanged();
   1510 
   1511     // Because CSSStyleSelector::checkOneSelector() and
   1512     // RenderTheme::isFocused() check if the frame is active, we have to
   1513     // update style and theme state that depended on those.
   1514     if (Node* node = m_frame->document()->focusedNode()) {
   1515         node->setNeedsStyleRecalc();
   1516         if (RenderObject* renderer = node->renderer())
   1517             if (renderer && renderer->style()->hasAppearance())
   1518                 renderer->theme()->stateChanged(renderer, FocusState);
   1519     }
   1520 
   1521     // Secure keyboard entry is set by the active frame.
   1522     if (m_frame->document()->useSecureKeyboardEntryWhenActive())
   1523         setUseSecureKeyboardEntry(activeAndFocused);
   1524 }
   1525 
   1526 void SelectionController::pageActivationChanged()
   1527 {
   1528     focusedOrActiveStateChanged();
   1529 }
   1530 
   1531 void SelectionController::updateSecureKeyboardEntryIfActive()
   1532 {
   1533     if (m_frame->document() && isFocusedAndActive())
   1534         setUseSecureKeyboardEntry(m_frame->document()->useSecureKeyboardEntryWhenActive());
   1535 }
   1536 
   1537 void SelectionController::setUseSecureKeyboardEntry(bool enable)
   1538 {
   1539     if (enable)
   1540         enableSecureTextInput();
   1541     else
   1542         disableSecureTextInput();
   1543 }
   1544 
   1545 void SelectionController::setFocused(bool flag)
   1546 {
   1547     if (m_focused == flag)
   1548         return;
   1549     m_focused = flag;
   1550 
   1551     focusedOrActiveStateChanged();
   1552 }
   1553 
   1554 bool SelectionController::isFocusedAndActive() const
   1555 {
   1556     return m_focused && m_frame->page() && m_frame->page()->focusController()->isActive();
   1557 }
   1558 
   1559 void SelectionController::updateAppearance()
   1560 {
   1561     ASSERT(!m_isDragCaretController);
   1562 
   1563 #if ENABLE(TEXT_CARET)
   1564     bool caretRectChanged = recomputeCaretRect();
   1565 
   1566     bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
   1567     bool shouldBlink = m_caretVisible
   1568         && isCaret() && (isContentEditable() || caretBrowsing);
   1569 
   1570     // If the caret moved, stop the blink timer so we can restart with a
   1571     // black caret in the new location.
   1572     if (caretRectChanged || !shouldBlink)
   1573         m_caretBlinkTimer.stop();
   1574 
   1575     // Start blinking with a black caret. Be sure not to restart if we're
   1576     // already blinking in the right location.
   1577     if (shouldBlink && !m_caretBlinkTimer.isActive()) {
   1578         if (double blinkInterval = m_frame->page()->theme()->caretBlinkInterval())
   1579             m_caretBlinkTimer.startRepeating(blinkInterval);
   1580 
   1581         if (!m_caretPaint) {
   1582             m_caretPaint = true;
   1583             invalidateCaretRect();
   1584         }
   1585     }
   1586 #endif
   1587 
   1588     // We need to update style in case the node containing the selection is made display:none.
   1589     m_frame->document()->updateStyleIfNeeded();
   1590 
   1591 #if PLATFORM(ANDROID)
   1592     return;
   1593 #endif
   1594 
   1595     RenderView* view = m_frame->contentRenderer();
   1596     if (!view)
   1597         return;
   1598 
   1599     VisibleSelection selection = this->selection();
   1600 
   1601     if (!selection.isRange()) {
   1602         view->clearSelection();
   1603         return;
   1604     }
   1605 
   1606     // Use the rightmost candidate for the start of the selection, and the leftmost candidate for the end of the selection.
   1607     // Example: foo <a>bar</a>.  Imagine that a line wrap occurs after 'foo', and that 'bar' is selected.   If we pass [foo, 3]
   1608     // as the start of the selection, the selection painting code will think that content on the line containing 'foo' is selected
   1609     // and will fill the gap before 'bar'.
   1610     Position startPos = selection.start();
   1611     Position candidate = startPos.downstream();
   1612     if (candidate.isCandidate())
   1613         startPos = candidate;
   1614     Position endPos = selection.end();
   1615     candidate = endPos.upstream();
   1616     if (candidate.isCandidate())
   1617         endPos = candidate;
   1618 
   1619     // We can get into a state where the selection endpoints map to the same VisiblePosition when a selection is deleted
   1620     // because we don't yet notify the SelectionController of text removal.
   1621     if (startPos.isNotNull() && endPos.isNotNull() && selection.visibleStart() != selection.visibleEnd()) {
   1622         RenderObject* startRenderer = startPos.deprecatedNode()->renderer();
   1623         RenderObject* endRenderer = endPos.deprecatedNode()->renderer();
   1624         view->setSelection(startRenderer, startPos.deprecatedEditingOffset(), endRenderer, endPos.deprecatedEditingOffset());
   1625     }
   1626 }
   1627 
   1628 void SelectionController::setCaretVisible(bool flag)
   1629 {
   1630     if (m_caretVisible == flag)
   1631         return;
   1632     clearCaretRectIfNeeded();
   1633     m_caretVisible = flag;
   1634     updateAppearance();
   1635 }
   1636 
   1637 void SelectionController::clearCaretRectIfNeeded()
   1638 {
   1639 #if ENABLE(TEXT_CARET)
   1640     if (!m_caretPaint)
   1641         return;
   1642     m_caretPaint = false;
   1643     invalidateCaretRect();
   1644 #endif
   1645 }
   1646 
   1647 void SelectionController::caretBlinkTimerFired(Timer<SelectionController>*)
   1648 {
   1649 #if ENABLE(TEXT_CARET)
   1650     ASSERT(m_caretVisible);
   1651     ASSERT(isCaret());
   1652     bool caretPaint = m_caretPaint;
   1653     if (isCaretBlinkingSuspended() && caretPaint)
   1654         return;
   1655     m_caretPaint = !caretPaint;
   1656     invalidateCaretRect();
   1657 #endif
   1658 }
   1659 
   1660 void SelectionController::notifyRendererOfSelectionChange(bool userTriggered)
   1661 {
   1662     m_frame->document()->updateStyleIfNeeded();
   1663 
   1664     if (!rootEditableElement())
   1665         return;
   1666 
   1667     RenderObject* renderer = rootEditableElement()->shadowAncestorNode()->renderer();
   1668     if (!renderer || !renderer->isTextControl())
   1669         return;
   1670 
   1671     toRenderTextControl(renderer)->selectionChanged(userTriggered);
   1672 }
   1673 
   1674 // Helper function that tells whether a particular node is an element that has an entire
   1675 // Frame and FrameView, a <frame>, <iframe>, or <object>.
   1676 static bool isFrameElement(const Node* n)
   1677 {
   1678     if (!n)
   1679         return false;
   1680     RenderObject* renderer = n->renderer();
   1681     if (!renderer || !renderer->isWidget())
   1682         return false;
   1683     Widget* widget = toRenderWidget(renderer)->widget();
   1684     return widget && widget->isFrameView();
   1685 }
   1686 
   1687 void SelectionController::setFocusedNodeIfNeeded()
   1688 {
   1689     if (isNone() || !isFocused())
   1690         return;
   1691 
   1692     bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
   1693     if (caretBrowsing) {
   1694         if (Node* anchor = enclosingAnchorElement(base())) {
   1695             m_frame->page()->focusController()->setFocusedNode(anchor, m_frame);
   1696             return;
   1697         }
   1698     }
   1699 
   1700     if (Node* target = rootEditableElement()) {
   1701         // Walk up the DOM tree to search for a node to focus.
   1702         while (target) {
   1703             // We don't want to set focus on a subframe when selecting in a parent frame,
   1704             // so add the !isFrameElement check here. There's probably a better way to make this
   1705             // work in the long term, but this is the safest fix at this time.
   1706             if (target && target->isMouseFocusable() && !isFrameElement(target)) {
   1707                 m_frame->page()->focusController()->setFocusedNode(target, m_frame);
   1708                 return;
   1709             }
   1710             target = target->parentOrHostNode();
   1711         }
   1712         m_frame->document()->setFocusedNode(0);
   1713     }
   1714 
   1715     if (caretBrowsing)
   1716         m_frame->page()->focusController()->setFocusedNode(0, m_frame);
   1717 }
   1718 
   1719 void SelectionController::paintDragCaret(GraphicsContext* p, int tx, int ty, const IntRect& clipRect) const
   1720 {
   1721 #if ENABLE(TEXT_CARET)
   1722     SelectionController* dragCaretController = m_frame->page()->dragCaretController();
   1723     ASSERT(dragCaretController->selection().isCaret());
   1724     if (dragCaretController->selection().start().anchorNode()->document()->frame() == m_frame)
   1725         dragCaretController->paintCaret(p, tx, ty, clipRect);
   1726 #else
   1727     UNUSED_PARAM(p);
   1728     UNUSED_PARAM(tx);
   1729     UNUSED_PARAM(ty);
   1730     UNUSED_PARAM(clipRect);
   1731 #endif
   1732 }
   1733 
   1734 PassRefPtr<CSSMutableStyleDeclaration> SelectionController::copyTypingStyle() const
   1735 {
   1736     if (!m_typingStyle || !m_typingStyle->style())
   1737         return 0;
   1738     return m_typingStyle->style()->copy();
   1739 }
   1740 
   1741 bool SelectionController::shouldDeleteSelection(const VisibleSelection& selection) const
   1742 {
   1743     return m_frame->editor()->client()->shouldDeleteRange(selection.toNormalizedRange().get());
   1744 }
   1745 
   1746 FloatRect SelectionController::bounds(bool clipToVisibleContent) const
   1747 {
   1748     RenderView* root = m_frame->contentRenderer();
   1749     FrameView* view = m_frame->view();
   1750     if (!root || !view)
   1751         return IntRect();
   1752 
   1753     IntRect selectionRect = root->selectionBounds(clipToVisibleContent);
   1754     return clipToVisibleContent ? intersection(selectionRect, view->visibleContentRect()) : selectionRect;
   1755 }
   1756 
   1757 void SelectionController::getClippedVisibleTextRectangles(Vector<FloatRect>& rectangles) const
   1758 {
   1759     RenderView* root = m_frame->contentRenderer();
   1760     if (!root)
   1761         return;
   1762 
   1763     FloatRect visibleContentRect = m_frame->view()->visibleContentRect();
   1764 
   1765     Vector<FloatQuad> quads;
   1766     toNormalizedRange()->textQuads(quads, true);
   1767 
   1768     // FIXME: We are appending empty rectangles to the list for those that fall outside visibleContentRect.
   1769     // It might be better to omit those rectangles entirely.
   1770     size_t size = quads.size();
   1771     for (size_t i = 0; i < size; ++i)
   1772         rectangles.append(intersection(quads[i].enclosingBoundingBox(), visibleContentRect));
   1773 }
   1774 
   1775 // Scans logically forward from "start", including any child frames.
   1776 static HTMLFormElement* scanForForm(Node* start)
   1777 {
   1778     for (Node* node = start; node; node = node->traverseNextNode()) {
   1779         if (node->hasTagName(formTag))
   1780             return static_cast<HTMLFormElement*>(node);
   1781         if (node->isHTMLElement() && toHTMLElement(node)->isFormControlElement())
   1782             return static_cast<HTMLFormControlElement*>(node)->form();
   1783         if (node->hasTagName(frameTag) || node->hasTagName(iframeTag)) {
   1784             Node* childDocument = static_cast<HTMLFrameElementBase*>(node)->contentDocument();
   1785             if (HTMLFormElement* frameResult = scanForForm(childDocument))
   1786                 return frameResult;
   1787         }
   1788     }
   1789     return 0;
   1790 }
   1791 
   1792 // We look for either the form containing the current focus, or for one immediately after it
   1793 HTMLFormElement* SelectionController::currentForm() const
   1794 {
   1795     // Start looking either at the active (first responder) node, or where the selection is.
   1796     Node* start = m_frame->document()->focusedNode();
   1797     if (!start)
   1798         start = this->start().deprecatedNode();
   1799 
   1800     // Try walking up the node tree to find a form element.
   1801     Node* node;
   1802     for (node = start; node; node = node->parentNode()) {
   1803         if (node->hasTagName(formTag))
   1804             return static_cast<HTMLFormElement*>(node);
   1805         if (node->isHTMLElement() && toHTMLElement(node)->isFormControlElement())
   1806             return static_cast<HTMLFormControlElement*>(node)->form();
   1807     }
   1808 
   1809     // Try walking forward in the node tree to find a form element.
   1810     return scanForForm(start);
   1811 }
   1812 
   1813 void SelectionController::revealSelection(const ScrollAlignment& alignment, bool revealExtent)
   1814 {
   1815     IntRect rect;
   1816 
   1817     switch (selectionType()) {
   1818     case VisibleSelection::NoSelection:
   1819         return;
   1820     case VisibleSelection::CaretSelection:
   1821         rect = absoluteCaretBounds();
   1822         break;
   1823     case VisibleSelection::RangeSelection:
   1824         rect = revealExtent ? VisiblePosition(extent()).absoluteCaretBounds() : enclosingIntRect(bounds(false));
   1825         break;
   1826     }
   1827 
   1828     Position start = this->start();
   1829     ASSERT(start.deprecatedNode());
   1830     if (start.deprecatedNode() && start.deprecatedNode()->renderer()) {
   1831         // FIXME: This code only handles scrolling the startContainer's layer, but
   1832         // the selection rect could intersect more than just that.
   1833         // See <rdar://problem/4799899>.
   1834         if (RenderLayer* layer = start.deprecatedNode()->renderer()->enclosingLayer()) {
   1835             layer->scrollRectToVisible(rect, false, alignment, alignment);
   1836             updateAppearance();
   1837         }
   1838     }
   1839 }
   1840 
   1841 void SelectionController::setSelectionFromNone()
   1842 {
   1843     // Put a caret inside the body if the entire frame is editable (either the
   1844     // entire WebView is editable or designMode is on for this document).
   1845 
   1846     Document* document = m_frame->document();
   1847     bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
   1848     if (!isNone() || !(document->rendererIsEditable() || caretBrowsing))
   1849         return;
   1850 
   1851     Node* node = document->documentElement();
   1852     while (node && !node->hasTagName(bodyTag))
   1853         node = node->traverseNextNode();
   1854     if (node)
   1855         setSelection(VisibleSelection(firstPositionInOrBeforeNode(node), DOWNSTREAM));
   1856 }
   1857 
   1858 bool SelectionController::shouldChangeSelection(const VisibleSelection& newSelection) const
   1859 {
   1860     return m_frame->editor()->shouldChangeSelection(selection(), newSelection, newSelection.affinity(), false);
   1861 }
   1862 
   1863 #ifndef NDEBUG
   1864 
   1865 void SelectionController::formatForDebugger(char* buffer, unsigned length) const
   1866 {
   1867     m_selection.formatForDebugger(buffer, length);
   1868 }
   1869 
   1870 void SelectionController::showTreeForThis() const
   1871 {
   1872     m_selection.showTreeForThis();
   1873 }
   1874 
   1875 #endif
   1876 
   1877 }
   1878 
   1879 #ifndef NDEBUG
   1880 
   1881 void showTree(const WebCore::SelectionController& sel)
   1882 {
   1883     sel.showTreeForThis();
   1884 }
   1885 
   1886 void showTree(const WebCore::SelectionController* sel)
   1887 {
   1888     if (sel)
   1889         sel->showTreeForThis();
   1890 }
   1891 
   1892 #endif
   1893