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